【问题标题】:NUnit test for Void function (Sending Email)NUnit 测试 Void 功能(发送电子邮件)
【发布时间】:2013-08-16 08:45:26
【问题描述】:

我有一个 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();
    }

【问题讨论】:

标签: c# asp.net unit-testing nunit


【解决方案1】:

在这种情况下,这将非常困难 - 除非您能够通过反射以某种方式切换 Email(正如 juhan_h in his answer 有趣地指出的那样,现在可能没那么难 ;))。

典型的解决方案是为你的类提供一个接口,例如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();
}

然后您可以向您的班级提供该工厂的存根,这将创建电子邮件模拟,您可以在其上验证正确的行为。

【讨论】:

    【解决方案2】:

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

    你真正想测试什么?

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

    【讨论】:

      【解决方案3】:

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

      更多关于假货的信息可以在MSDN找到。

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

      【讨论】:

      【解决方案4】:

      如何做到这一点?

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

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

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

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

      【讨论】:

        【解决方案5】:

        您要写的是integration test,而不是unit test

        如果您想测试您的代码是否调用了某个负责发送电子邮件的函数,那么您想通过使用某种模拟框架(例如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 我个人不喜欢模拟静态或具体的组件。它会导致不良习惯和不良代码。但是,以正确方式使用的工具可能会很有用,这可能是您测试这部分代码的最佳方式。

        最后确保你测试的是正确的东西。你不需要测试微软是否正确地编写了 System.Email 组件,你只需要确保你正确地调用了这些组件.

        【讨论】:

          猜你喜欢
          • 2014-11-30
          • 2020-03-26
          • 2014-05-23
          • 1970-01-01
          • 2012-02-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-10
          相关资源
          最近更新 更多