简体   繁体   English

借助 Mock,如何避免 xunit.net 中的基调用方法

[英]How to avoid base called method in xunit.net thanks to Mock

I'm trying to code unit test for my CutomSmtpMailer.我正在尝试为我的 CutomSmtpMailer 编写单元测试代码。 My CutomSmtpMailer inherit from SmtpClient.我的 CutomSmtpMailer 继承自 SmtpClient。

Here is how my class looks like:这是我的 class 的样子:

public class CutomSmtpMailer : SmtpClient
{
    private void SendMail(MailMessage mailMessage)
    {
        //DoSomeStuff
        Send(mailMessage); //base.Send(mailMessage)
    }
}

I would like to test my custom code without sending mail: I want to avoid the call of "Send(mailMessage)" by replacing it by an empty Action, not knowing if it has been called .我想在不发送邮件的情况下测试我的自定义代码:我想通过将其替换为空操作来避免调用“Send(mailMessage)”,不知道它是否已被调用 I knew how to mock an instance when i use DI, but i don't want to inject the SMTPclient (in fact i've numberous case with inheritence here is a simple exemple)当我使用 DI 时,我知道如何模拟一个实例,但我不想注入 SMTPclient(事实上,我这里有很多带有继承的案例,这是一个简单的例子)

public class TestCutomSmtpMailer
{
    public CutomSmtpMailer Get()
    {
        return new CutomSmtpMailer();
    }

    [Fact]
    public void SendMail()
    {
        CutomSmtpMailer service = Get();
        MailMessage mailMessage = new MailMessage();
        // Find on web but not available :(
        Mock.Arrange(() => new SmtpClient().Send()).Returns(null).IgnoreInstance();
        service.SendMail(mailMessage);
    }
}

How to replace/Mock the Parent class method by an empty func to avoid sending mail?如何用空函数替换/模拟父 class 方法以避免发送邮件?

Thanks in advance提前致谢

Since you don't want to inject the SmtpClient using dependency injection , you could go the ugly way and add an internal constructor and delegate to CustomSmtpMailer to aid in mocking and testing.由于您不想使用依赖注入注入SmtpClient ,因此您可以采用丑陋的方式 go 并添加内部构造函数并委托给CustomSmtpMailer以帮助 mocking 和测试。 Please be aware that this approach is not very clean.请注意,这种方法不是很干净。 It will result in having code that is purely for testing in your product assembly which is usually not a good idea.这将导致拥有纯粹用于在您的产品组装中进行测试的代码,这通常不是一个好主意。

It does however solve your problem as described and gets you around having to use dependency injection .但是,它确实解决了您所描述的问题,并使您不必使用依赖注入

public class CustomSmtpMailer : SmtpClient {

    internal delegate void SendInternal(MailMessage message);

    private SendInternal _sendAction;

    // make sure all your constructors call this one.
    // this will make the call to base.Send(MailMessage) the default behaviour.
    public CustomSmtpMailer() {
        _sendAction = delegate (MailMessage message) { Send(message); };
    }

    // customizes the SendMail(MailMessage) behaviour for testing purposes.
    internal CustomSmtpMailer(SendInternal sendAction) {
        _sendAction = sendAction;
    }

    private void SendMail(MailMessage mailMessage) {
        //DoSomeStuff

        _sendAction(mailMessage);
    }

}

Make the internal members visible to your test project by adding this to your AssemblyInfo.cs in your project.通过将其添加到项目中的AssemblyInfo.cs使内部成员对您的测试项目可见。

using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("My.Test.Assembly.Name")]

In your unit test you can use the internal constructor to configure the base call.在您的单元测试中,您可以使用内部构造函数来配置基本调用。

[Fact]
public void SendMail() {

    CustomSmtpMailer service = new CustomSmtpMailer(delegate (MailMessage message) {
        Console.WriteLine("I'm a custom Action that can be used for testing");
    });
    MailMessage mailMessage = new MailMessage();
    // Find on web but not available :(
    Mock.Arrange(() => new SmtpClient().Send()).Returns(null).IgnoreInstance();
    service.SendMail(mailMessage);

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM