Если я создам макет для класса электронной почты, будет ли он отправлять реальное письмо? - PullRequest
0 голосов
/ 05 марта 2019

Простой вопрос с теоретической точки зрения.Если у меня есть Email класс с Send() методом внутри, который отвечает за отправку электронной почты.Send() метод объявлен в интерфейсе с именем IEmail.Давайте предположим, что я буду moq этот метод как IEmail интерфейс в моем модульном тесте.Затем, когда я Setup moq с Send() и позже использую метод Verify(), тогда я предполагаю, что реальное письмо не будет отправлено, а только проверит, правильно ли был вызван метод Send().Я прав?Во-вторых, чтобы проверить реальную Send(), чтобы действительно отправить электронную почту, я должен использовать интеграционный тест.Это все правильно?

1 Ответ

2 голосов
/ 05 марта 2019

Предположительно, то, что вы тестируете, не соответствует классу Email. Если это конкретный класс, который отправляет электронное письмо, то вызов Send отправит (и, вероятно, должен) отправить электронное письмо.

Mocking будет полезен для тестирования класса, который зависит от вашего IEmail интерфейса. Это позволяет вам проверить, что ваш класс делает то, что ожидается с интерфейсом, от которого он зависит. В этом случае вы не захотите отправить электронное письмо. Вы просто хотите проверить, что ваш класс говорит IEmail отправить электронное письмо.

Вот надуманный пример класса, который зависит от интерфейса IEmail для отправки электронной почты.

public class ClassThatSendsEmail
{
    private readonly IEmail _email;

    public ClassThatSendsEmail(IEmail email)
    {
        _email = email;
    }

    public void DoSomethingThatCausesAnEmailToGetSent()
    {
        var message = new Message {To = "bob@bob.com", Body = "Hi, Bob!"};
        _email.Send(message);
    }
}

... и вот некоторые другие типы, которые я собрал только для тестирования:

public interface IEmail
{
    void Send(Message message);
}

public class Message
{
    public string To { get; set; }
    public string Body { get; set; }
}

Вот очень простой тест, который будет издеваться над IEmail.

public class Tests
{
    [TestCase]
    public void MyClassSendsAnEmail()
    {
        var emailMock = new Mock<IEmail>();
        emailMock.Setup(x=>x.Send(It.IsAny<Message>())).Verifiable();
        var subject = new ClassThatSendsEmail(emailMock.Object);
        subject.DoSomethingThatCausesAnEmailToGetSent();
        emailMock.Verify(x=>x.Send(It.IsAny<Message>()));
    }
}

Чтобы ответить на ваш вопрос напрямую, письмо не будет отправлено, потому что конкретный класс Email нигде не показан. Я даже не создал один. Мой класс зависит только от интерфейса, поэтому я могу проверить его еще до того, как напишу реализацию IEmail. Тест только собирается проверить, что мой класс вызвал метод макета Send.

(Это отличный способ предотвратить связывание. Я не хочу, чтобы мой класс был тесно связан с каким-то другим классом, который отправляет электронные письма, чтобы один класс работал только с другим. Если первый класс работает, как ожидалось когда я даже не создал второй класс, тогда он не связан со вторым классом.)

Иногда удобно написать test double, который является реальным классом, который реализует интерфейс только для целей тестирования. Вы можете делать то же самое с Moq, но иногда весь код установки усложняется, а использование двойного теста просто облегчает чтение.

Итак, вот двойной тест для IEmail. Когда вы отправляете сообщение, оно собирается добавить сообщение в список. Таким образом, после запуска теста вы можете посмотреть, что находится в списке, чтобы убедиться, что отправлено правильное письмо:

public class EmailListDouble : List<Message>, IEmail
{
    public void Send(Message message)
    {
        Add(message);
    }
}

Теперь вы можете легко написать тест, который проверяет, что IEmail.Send был вызван и что ожидаемое сообщение было отправлено:

[TestCase]
public void MyClassSendsAnEmail()
{
    var email = new EmailListDouble();
    var subject = new ClassThatSendsEmail(email);
    subject.DoSomethingThatCausesAnEmailToGetSent();
    Assert.True(email.Any(message=> message.To == "bob@bob.com" && message.Body.Contains("Bob")));
}

Moq великолепен, но иногда настройка может не только стать немного громоздкой, но и усложнить определение того, что тестируется. Иногда простое использование тестового двойника делает работу, и это проще.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...