Как избежать метода базового вызова в xunit.net благодаря Mock - PullRequest
0 голосов
/ 23 октября 2019

Я пытаюсь написать кодовый тест для моего CutomSmtpMailer. Мой CutomSmtpMailer унаследован от SmtpClient.

Вот как выглядит мой класс:

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

Я хотел бы проверить свой пользовательский код без отправки почты: Я хочу избежать вызова«Отправить (mailMessage)», заменив его пустым действием, не зная, было ли оно вызвано . Я знал, как смоделировать экземпляр, когда я использую DI, но я не хочу внедрять SMTP-клиент (на самом деле у меня есть ряд случаев с наследованием, это простой пример)

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);
    }
}

Как заменить/ Перемешивать метод класса Parent пустой функцией, чтобы избежать отправки почты?

Заранее спасибо

1 Ответ

1 голос
/ 24 октября 2019

Поскольку вы не хотите внедрять SmtpClient, используя внедрение зависимостей , вы можете пойти ужасным путем и добавить внутренний конструктор и делегировать CustomSmtpMailer, чтобы помочьв издевательствах и испытаниях. Пожалуйста, имейте в виду, что этот подход не очень чистый. Это приведет к наличию кода, предназначенного исключительно для тестирования в сборке вашего продукта, что, как правило, не очень хорошая идея.

Однако это решает вашу проблему, как описано, и помогает вам использовать внедрение зависимостей .

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);
    }

}

Сделайте внутренних участников видимыми для вашего тестового проекта, добавив это в AssemblyInfo.cs в вашем проекте.

using System.Runtime.CompilerServices;

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

В своем модульном тесте вы можете использоватьвнутренний конструктор для настройки базового вызова.

[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);

}
...