3

我有一个 void 功能,它发送电子邮件。我需要为此功能编写测试。如何才能做到这一点?

public void SendAdminMail(string subject, string body, string adminAddress)
    {

        var email = Email.
            From(ConfigurationManager.AppSettings["Mail.NoReply.Address"].ToString(CultureInfo.InvariantCulture)).
            To(adminAddress).
            Subject(subject).
            Body(body).
            UsingClient(GetOfficeClient());
        email.Message.SubjectEncoding = Encoding.UTF8;
        email.Message.BodyEncoding = Encoding.UTF8;

        email.Send();
    }
4

5 回答 5

3

在这种情况下,这将非常困难-除非您能够通过反射以某种方式进行切换(正如juhan_h 在他的回答Email中有趣地指出的那样,现在可能并不那么难;))。

典型的解决方案是为您的类提供一个接口,例如interface EmailFactory. 然后你会有:

private EmailFactory emailFactory;
public void SendAdminMail(string subject, string body, string adminAddress)
{
    var email = emailFactory
        .From(ConfigurationManager
                  .AppSettings["Mail.NoReply.Address"]
                  .ToString(CultureInfo.InvariantCulture))
        .To(adminAddress)
        .Subject(subject)
        .Body(body)
        .UsingClient(GetOfficeClient());

    email.Message.SubjectEncoding = Encoding.UTF8;
    email.Message.BodyEncoding = Encoding.UTF8;

    email.Send();
}

然后你可以为你的班级提供这个工厂的存根,它会创建电子邮件模拟,你可以在上面验证正确的行为。

于 2013-08-16T08:50:15.597 回答
2

如果您碰巧拥有 Visual Studio 2012 Ultimate 或 Premium,那么您可以为该程序集生成 Fakes 程序System.Net.Mail集并使用它。

更多关于 Fakes 的信息可以在MSDN上找到。

如果您没有 VS2012 Ultimate 或 Premium,那么我的回答完全没用 :)

于 2013-08-16T08:49:33.563 回答
2

我开始认为拔下网络电缆时单元测试应该可以工作。

你真正想测试什么?

您可以使用 mock 或 fake 并验证您是否按预期调用了方法。
能够将此类存根并在其他地方使用存根以确保其余测试不会在每次运行时都发送电子邮件,这可能会被证明更有用。

于 2013-08-16T08:51:29.360 回答
1

您要编写的是集成测试而不是单元测试

如果您想测试您的代码是否调用了一些负责发送电子邮件的函数,那么您想通过使用某种模拟框架(例如NSubstitute )来编写单元测试。

[Test]
public void ShouldSendEmail()
{
    IEmailService mockEmailService = Substitute.For<IEmailService>();
    MyEmailSendingThingy thingUnderTest = new MyEmailSendingThingy(mockEmailService);

    thingUnderTest.DoSomeWorkThatInvolvesSendingEmails();

    mockEmailService.Received().SendEmail("foo@foo.foo", "bar@bar.bar", "Subject", "Some Text");
}

如果您想测试您的应用程序是否真的发送了一封电子邮件,您需要编写一个集成测试。您可以通过多种方式实现这一目标。

  1. 编写一个等待一段时间的测试,然后从测试电子邮件帐户中检索电子邮件并验证它是否收到了预期的消息。
  2. 将电子邮件发送到内部 SMTP 服务器,该服务器设置为将电子邮件存储在投递文件夹中,然后可以通过测试代码进行检查。
  3. 模拟一个 SMTP 端点并模仿调用 SMTP 服务器的东西所期望的响应。然后,您可以使用您的端点验证它是否收到了预期的电子邮件。
  4. 使用Moles或 Fakes模拟 System.Mail 组件。

1 和 2 需要付出很多努力,并且您必须考虑发送电子邮件的异步性质。这意味着您将不得不让您的程序休眠或使用某种触发器来等待电子邮件到达其目的地,这应尽可能避免。

3 是我个人的选择,有三个原因。您可以在测试过程中托管它,从而更轻松地进行断言。其次,它是可重用的,可以在任何测试框架中使用。第三,作为奖励,您可以更好地了解电子邮件的工作原理。

4 就我个人而言,我不喜欢模拟静态或具体的组件。这会导致不良习惯和不良代码。但是,以正确方式使用的工具可能会很有用,这可能是您测试这部分代码的最佳方式。

最后确保你正在测试正确的东西。您不需要测试 Microsoft 是否正确编写了 System.Email 组件,您只需要确保正确调用组件即可。

于 2013-08-16T09:53:46.693 回答
1

如何才能做到这一点 ?

除非您使用某些库或框架来做很多变通方法,否则测试此方法并不简单,因为您的方法违反了 SRP 原则。

尽管您的方法称为 SendAmdinMail,但实际上只有一个语句处理发送,存在email.Send(),其余方法是使用 .NET API 构建邮件消息。

您应该将此方法分解为不同的部分,例如 CreateMailBody、CreateHeader、LoadMailConfig,并将邮件发送隐藏在抽象(接口、抽象类)后面,以便您可以创建邮件发送服务的模拟。

这样你也可以测试邮件正文的内容,可以测试收件人等。

于 2013-08-16T09:16:24.750 回答