【问题标题】:How to set up an email or notification service for asp.net mvc如何为 asp.net mvc 设置电子邮件或通知服务
【发布时间】:2011-01-14 01:10:49
【问题描述】:

如何创建可以模拟和单元测试的电子邮件发送通知服务类?

我的服务位于另一个层,即类库。我试图不导入 smtp 客户端,但如果这是不可避免的,那么它没有问题。这就是我现在拥有的:

public class EmailNotificationService : INotificationService
{
    private readonly EmailNotification _emailNotification;

    public EmailNotificationService(EmailNotification emailNotification)
    {
        _emailNotification = emailNotification;
    }

    public void Notify()
    {
        using (var mail = new MailMessage())
        {
            //If no replyto was passed in the notification, then make it null.
            mail.ReplyTo = string.IsNullOrEmpty(_emailNotification.ReplyTo) ? null : new MailAddress(_emailNotification.ReplyTo);

            mail.To.Add(_emailNotification.To);
            mail.From = _emailNotification.From;
            mail.Subject = _emailNotification.Subject;
            mail.Body = _emailNotification.Body;
            mail.IsBodyHtml = true;

            //this doesn't seem right.
            SmtpClient client = new SmtpClient();
            client.Send(mail);
        }
    }
}

public class EmailNotification
{
    public EmailNotification()
    {
        To = "";
        ReplyTo = "";
        Subject = "";
        Body = "";
    }
    public string To { get; set; }
    public string ReplyTo { get; set; }
    public string Subject { get; set; }
    public string Body { get; set; }

}

【问题讨论】:

  • 发送电子邮件实际上比听起来和应该的要复杂得多。 codinghorror.com/blog/2010/04/…
  • 你想在这里测试什么?在这门课中你可以进行单元测试的内容很少。测试它实际上发送电子邮件是一个集成测试。
  • 您希望 EmailNotificationService 做什么?当然是发送电子邮件......我认为你的设计过于复杂
  • 您所面临的单元测试是否存在一个特定问题,即此类正在抛出?这门课看起来不错,我怀疑你的测试才是真正的问题所在。

标签: asp.net-mvc design-patterns asp.net-mvc-3


【解决方案1】:

如果您不想导入 System.Net.Mail 库,则必须使用接口。请注意,这对您的单元测试并没有太大帮助

public interface IEmailSender{
     void Send(EmailNotification emailNotification);
}

然后在您的 EmailNotificationService 类中,您可以添加以下属性或在构造函数中传入 IEmailSender

private IEmailSender emailSender;

public IEmailSender EmailSender
{
     get{
          if(this.emailSender == null){
               //Initialize new EmailSender using either
               // a factory pattern or inject using IOC 
          }
          return this.emailSender
     }
     set{
          this.emailSender = value;
     }
}

你的 Notify 方法会变成

public void Notify()
{
    EmailSender.Send(_emailNotification);
}

然后您将创建一个实现 IEmailSender 接口的具体类

public class MyEmailSender: IEmailSender
{
     public void Send(EmailNotification emailNotification)
     {
        using (var mail = new MailMessage())
        {
            //If no replyto was passed in the notification, then make it null.
            mail.ReplyTo = 
                    string.IsNullOrEmpty(_emailNotification.ReplyTo) ? null : 
                    new MailAddress(_emailNotification.ReplyTo);

            mail.To.Add(emailNotification.To);
            mail.From = emailNotification.From;
            mail.Subject = emailNotification.Subject;
            mail.Body = emailNotification.Body;
            mail.IsBodyHtml = true;

            SmtpClient client = new SmtpClient();
            client.Send(mail);
        }
     }
}

【讨论】:

  • 与其拥有一个由 IEmailSender 接口的私有字段支持的属性,我宁愿将它作为构造函数参数传递。但是无论哪种方式,除了您的 getter 返回适当的实例(不在原始代码中)之外,您仍然没有任何要测试的东西,因此 OP 在他的原始实现中仍然没有任何可以进行单元测试的东西。
  • 真的没有太多要测试的东西。就像你说的,它要么发送邮件,要么不发送邮件
猜你喜欢
  • 2010-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-09
  • 2015-03-14
  • 1970-01-01
  • 2014-10-07
  • 1970-01-01
相关资源
最近更新 更多