如何单元测试电子邮件发送?

时间:2011-03-09 22:22:35

标签: c# .net unit-testing

我想使用.NET(C#)框架或任何兼容的库测试我的电子邮件发送功能,任何建议如何操作?

9 个答案:

答案 0 :(得分:31)

如果您只需要测试发送电子邮件,则可以像这样配置.config文件

<system.net>
    <mailSettings>
        <smtp deliveryMethod="SpecifiedPickupDirectory">
            <specifiedPickupDirectory pickupDirectoryLocation="C:\TempMail" />
        </smtp>
    </mailSettings>
</system.net>

使用这些设置,您的邮件不会通过网络发送,而是作为您在pickupDirectoryLocation属性中配置的文件夹中的.eml扩展名的物理文件删除。您可以在System.IO命名空间中的类的帮助下检查它们。

MSDN文档为here

答案 1 :(得分:19)

我不同意在单元测试期间实际发送电子邮件的概念。这要求IMO遇到很多麻烦,并且反对单元测试应该是什么。

在我的应用中,我有一个IMailManager界面,其中包含SendPasswordResetEmail(string emailAddress)等方法。我在单元测试期间模拟了这个对象,并确保我的组件正在调用正确的邮件管理器方法。

MailManager的实际生产实施通常在内部使用System.Net.Mail.SmtpClient,您无需进行测试。让微软测试一下。您需要做的就是确保在部署时正确设置smtp设置,这不应该是单元测试的关注点。

如果您需要测试您的邮件组件本身,即确保它生成正确的邮件正文等,我建议嘲笑将该功能隔离到自包含单元测试中所需的内容。

答案 2 :(得分:12)

您不需要测试实际的电子邮件发送功能;这是.NET框架的一部分,已经过测试。

单元测试需要的是电子邮件创建业务逻辑。将其封装在这样的服务中:

public interface IPasswordResetEmailCreator
{
    MailMessage Create(string emailAddress);
}

并实施它。然后为此实现编写单元测试,并验证它返回的 MailMessage 是否符合您的要求。

使用SpecsFor框架进行此单元测试的示例实现:

public class PasswordResetEmailCreatorSpecs
{
    public class given_a_registered_user : SpecsFor<PasswordResetEmailCreator>
    {
        private string _emailAddress;
        private MailMessage _email;

        protected override void Given()
        {
            _emailAddress = "user@example.org";
        }

        protected override void When()
        {
            _email = SUT.Create(_emailAddress);
        }

        [Test]
        public void then_the_body_must_contain_the_reset_uri()
        {
            _email.Body.ShouldContain("/Password/Reset/");
        }

        [Test]
        public void then_the_email_must_be_for_the_user()
        {
            _email.To[0].Address.ShouldEqual(_emailAddress);
        }

        [Test]
        public void then_the_subject_must_be_the_expected()
        {
            _email.Subject.ShouldEqual("Your email reset link");
        }
    }
}

答案 3 :(得分:0)

我通常有一个“OverrideEmailAddress”设置,我将其设置为我自己的电子邮件,然后您运行的任何电子邮件测试都不会发送给您的客户或他们最初会去的人。我有一个帮助方法,我发送所有电子邮件,如果存在,此方法将使用该设置。您可以选择添加原始收件人所在的电子邮件底部。

如果您需要确认已收到电子邮件,则必须编写一些代码以实际检查电子邮件地址,然后确认邮件是否正确。

不确定这是不是你的意思。

答案 4 :(得分:0)

我可能会在.NET SmtpClient类之上编写一个非常精简的抽象层。然后我可以用模型类替换单元测试。当然,你无法对封装器进行单元测试,但它无论如何都应该是微不足道的,几乎不会改变。

答案 5 :(得分:0)

有一种非常简单的方法可以在审批测试中测试电子邮件内容(www.approvaltests.com或nuget)。守则很简单:

EmailApprovals.Verify(mail);

这将创建.eml文件,并允许您在outlook中查看结果。此外,一旦您批准结果(将文件重命名为.approved),测试将通过而无需打开outlook。 (这与@whylee提到的过程非常相似,但不使用配置文件。)

I have published a short video on the process on YouTube

答案 6 :(得分:0)

如果您想测试它,我建议您查看mail4net:www.mail4net.com

它是一种商业产品,但它允许您使用虚假SMTP服务发送电子邮件,然后查询虚假邮件。

// Create Mail4Net FakeClient.
var client = new Mail4Net.Client.FakeClient();

// Send email.
client.Send(from, to, subject, body);

然后,您可以查询客户端:

// Count the number of emails sent.
var count = client.Count();

// Get first email.
var message = client[0];

答案 7 :(得分:0)

我的快速和肮脏的方法与bool非常相似,除了它不需要触摸任何配置文件(因为我可能需要不同的单元测试的不同设置)

在您的电子邮件发送代码中

if (ConfigurationManager.AppSettings["smtpDir"] == null)
    smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
else
{
    smtp.DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory;
    smtp.PickupDirectoryLocation = ConfigurationManager.AppSettings["smtpDir"];
}

在您的单元测试中

ConfigurationManager.AppSettings["smtpDirectory"] = dir;

//do some testing then change it back

ConfigurationManager.AppSettings["smtpDirectory"] = null;

PS。我知道所有的缺点,但万一有人需要这个......

答案 8 :(得分:0)

我用于集成测试的一种快速而肮脏的解决方案是简单地实现一个电子邮件管理器,该电子邮件管理器将电子邮件存储在内存中-然后可以在测试断言中进行访问-而不是实际发送。目前,每个测试发送的电子邮件最大数量为2,所以我想这就是为什么在这种情况下就足够了。

当然,您必须在每次测试后清理此已发送电子邮件的内存列表。