Предположительно, то, что вы тестируете, не соответствует классу 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 великолепен, но иногда настройка может не только стать немного громоздкой, но и усложнить определение того, что тестируется. Иногда простое использование тестового двойника делает работу, и это проще.