【问题标题】:Unit-testing mail sending with postal and moq使用 postal 和 moq 对邮件发送进行单元测试
【发布时间】:2016-10-31 17:08:36
【问题描述】:

System.ArgumentNullException 在调用测试中的mail.Send() 时从System.Web.HttpBrowserCapabilities 构造函数中抛出。它需要httpBrowserCapabilities参数。

我使用过的代码:

电子邮件模型:

public class EmailModel :Email
{
    public EmailModel() :base("EmailModel")
    {

    }
    public string To = "**********@gmail.com";

    [Display(ResourceType = typeof(Resource), Name = "Name")]
    [Required(ErrorMessageResourceName = "Error_NameRequired", ErrorMessageResourceType = typeof(Resource))]
    public string Name { get; set; }

    [DataType(DataType.EmailAddress)]
    [Display(ResourceType = typeof (Resource), Name = "Email")]
    [Required(ErrorMessageResourceName = "Error_EmailRequired", ErrorMessageResourceType = typeof(Resource))]
    [RegularExpression(".+@.+", ErrorMessageResourceName = "Error_EmailWrong", ErrorMessageResourceType = typeof(Resource))]
    public string Email { get; set; }

    [Display(ResourceType = typeof(Resource), Name = "Topic")]
    [Required(ErrorMessageResourceName = "Error_TopicRequired", ErrorMessageResourceType = typeof(Resource))]
    public string Topic { get; set; }

    [Display(ResourceType = typeof(Resource), Name = "Massage")]
    [DataType(DataType.MultilineText)]
    [Required(ErrorMessageResourceName = "Error_MassageRequired", ErrorMessageResourceType = typeof(Resource))]
    public string Massage { get; set; }
}

查看消息:

@model *******.Models.EmailModel
@{
    Layout = null;
}
To: @Model.To
Subject: @Model.Topic

The massage from @Model.Name @Model.Email
Massage text:
@Model.Massage

单元测试:

public class EmailSetter
{
    public const string DefaultName = "NameTest";
    public const string DefaultEmail = "EmailTest@domaintest.test";
    public const string DefaultTopic = "TopicTest";
    public const string DefaultMassage = "Massage test.";
    public EmailModel GetEmail(string Name = DefaultName, string Topic = DefaultTopic, string Email = DefaultEmail, string Massage = DefaultMassage)
    {
        EmailModel email = new EmailModel();
        email.Name = Name;
        email.Topic = Topic;
        email.Email = Email;
        email.Massage = Massage;
        return email;
    }
}
[TestClass]
public class MailTests
{
    [TestMethod]
    public void MailSendWithRightModel()
    {
        //Arrange
        HomeController controller = new HomeController();
        Mock<EmailModel> email = new Mock<EmailModel>();
        email.Object.Name = EmailSetter.DefaultName;
        email.Object.Email = EmailSetter.DefaultName;
        email.Object.Topic = EmailSetter.DefaultTopic;
        email.Object.Massage = EmailSetter.DefaultMassage;
        //Act
        controller.Contact(email.Object);
        //Assert
        email.Verify(mail => mail.Send());
    }
}

来自测试的控制器:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Contact(EmailModel emailModel)
{
    if(ModelState.IsValid)
    {
        ViewBag.Send = true;
        emailModel.Send();
        ModelState.Clear();
    }
    return View(emailModel);
}

我尝试过的(在单元测试方法中):

  1. 通过new BrowserCapabilitiesFactory创建new HttpBrowserCapabilities

  2. HttpBrowserCapabilities 创建new HttpBrowserCapabilitiesWrapper 对象

任何想法如何使代码不抛出异常? (即让当前的 HttpBrowserCapabilitiesWrapper 获取现有的 HttpBrowserCapabilities):)

【问题讨论】:

  • 您已经发表了多项声明。但是你的问题是什么?
  • 您是在尝试发送实际的电子邮件(集成测试)还是打算模拟电子邮件的发送?很可能电子邮件正在尝试发送电子邮件,但尚未为测试配置正确的依赖项。
  • 我正在尝试测试是否会调用 Send 方法,是否将正确的模型提供给控制器。我也认为问题出在正常应用程序启动期间创建的依赖项中。

标签: c# asp.net-mvc unit-testing moq postal


【解决方案1】:

来源:Postal Unit Testing

在对使用 Postal 的代码进行单元测试时,您可能需要验证 将发送一封电子邮件,而无需实际发送。

Postal 提供了一个接口IEmailService 和一个实现, EmailService,实际上是发送电子邮件。

假设您使用某种 IoC 容器,请将其配置为注入 IEmailService 进入你的控制器。

然后使用该服务发送电子邮件对象(而不是调用 Email.Send())。

public class HomeController : Controller {

    readonly IEmailService emailService;

    public HomeController(IEmailService emailService) {
        this.emailService = emailService;
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Contact(EmailModel email) {
        if(ModelState.IsValid) {
            emailService.Send(email);
            ViewBag.Send = true;
            ModelState.Clear();
        }
        return View(email);
    }
}

通过创建 IEmailService 的模拟来测试此控制器 界面。

[TestClass]
public class MailTests {
    [TestMethod]
    public void MailSendWithRightModel() {
        //Arrange
        var mockService = new Mock<IEmailService>();
        var controller = new HomeController(mockService.Object);
        var email = new EmailSetter().GetEmail();

        //Act
        controller.Contact(email);

        //Assert
        mockService.Verify(m => m.Send(email));
    }
}

【讨论】:

  • 是的,我应该更好地阅读文档。如果有人会使用我的代码和这个答案代码: var email = EmailSetter.GetEmail();应改为 EmailModel email = (new EmailSetter()).GetEmail();
  • Thought 是一个静态工厂方法。固定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-24
  • 1970-01-01
  • 2012-06-01
  • 2011-07-12
相关资源
最近更新 更多