C# 如果我为一个email类创建一个Mock,它会发送一封真正的email吗?

C# 如果我为一个email类创建一个Mock,它会发送一封真正的email吗?,c#,.net,unit-testing,moq,C#,.net,Unit Testing,Moq,从理论角度来看,这是一个简单的问题。如果我有Email类,里面有Send()方法,负责发送电子邮件Send()方法在名为IEmail的接口中声明。让我们假设在我的单元测试中,我将moq该方法作为IEmail接口。然后,当我使用Send()设置moq,然后使用Verify()方法时,我假设不会发送真正的电子邮件,而只检查是否正确调用了Send()方法。我说得对吗?其次,要检查realSend()要真正发送电子邮件,我应该使用集成测试。这一切都正确吗?您可能测试的不是实际的电子邮件类。如果它是一个发

从理论角度来看,这是一个简单的问题。如果我有
Email
类,里面有
Send()
方法,负责发送电子邮件
Send()
方法在名为
IEmail
的接口中声明。让我们假设在我的单元测试中,我将
moq
该方法作为
IEmail
接口。然后,当我使用
Send()
设置
moq,然后使用
Verify()
方法时,我假设不会发送真正的电子邮件,而只检查是否正确调用了
Send()
方法。我说得对吗?其次,要检查real
Send()
要真正发送电子邮件,我应该使用集成测试。这一切都正确吗?

您可能测试的不是实际的
电子邮件类。如果它是一个发送电子邮件的具体类,那么调用
Send
将(而且可能应该)发送电子邮件

模拟对于测试依赖于
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);
    }
}
下面是一个人工设计的类示例,它依赖
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>()));
    }
}
现在,您可以轻松编写一个测试,验证是否调用了
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很好,但有时设置不仅会变得有点麻烦,而且会使测试内容更难确定。有时,只需使用双重测试就可以完成任务,而且更容易。

您可能测试的不是实际的
电子邮件类。如果它是一个发送电子邮件的具体类,那么调用
Send
将(而且可能应该)发送电子邮件

模拟对于测试依赖于
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);
    }
}
下面是一个人工设计的类示例,它依赖
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>()));
    }
}
现在,您可以轻松编写一个测试,验证是否调用了
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很好,但有时设置不仅会变得有点麻烦,而且会使测试内容更难确定。有时候,只需使用双重测试就可以完成任务,而且更简单。

moq
生成的方法除了跟踪调用的方法外,什么也做不了。是的,您是正确的。
moq
生成的方法除了跟踪调用的方法外,什么也做不了。是的,您是正确的。集成测试看起来是什么样子,你能在此基础上给出一些例子吗?在你的第二次测试中,真正的电子邮件将被发送,因为我没有看到moq?那么这更像是集成测试吗?我在谷歌上搜索并发现了这个,我从来都不知道:。假设您使用的是SMTP客户端,您可以将其配置为将电子邮件“发送”到文件夹,然后您可以读取并检查它们。不过,我从未测试过实际的电子邮件。如果我使用的是框架类,那么似乎没有必要。这看起来更像是对基础设施的测试。但我想这一切都是有道理的。集成测试会是什么样子,你能给出一些基于这个的例子吗?在你的第二次测试中,真正的电子邮件将被发送,因为我没有看到moq?那么这更像是集成测试吗?我在谷歌上搜索并发现了这个,我从来都不知道:。假设您使用的是SMTP客户端,您可以将其配置为将电子邮件“发送”到文件夹,然后您可以读取并检查它们。不过,我从未测试过实际的电子邮件。如果我使用的是框架类,那么似乎没有必要。这看起来更像是对基础设施的测试。但我想一切都有理由。