1

System.ArgumentNullException is thrown from System.Web.HttpBrowserCapabilities constructor when mail.Send() from test called. It requires httpBrowserCapabilities parameter.

Code I have used:

EmailModel:

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; }
}

View of message:

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

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

UnitTest :

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());
    }
}

Controller from test:

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

What I have tried (in unit test method):

  1. creating new HttpBrowserCapabilities through new BrowserCapabilitiesFactory

  2. creating new HttpBrowserCapabilitiesWrapper with HttpBrowserCapabilities object

Any ideas how to make code not to throw exception? (i.e. make current HttpBrowserCapabilitiesWrapper get existing HttpBrowserCapabilities) :)

Nkosi
  • 235,767
  • 35
  • 427
  • 472
Cute pumpkin
  • 342
  • 3
  • 17
  • 2
    You have made several statements. But what is your question? – Jasen Oct 31 '16 at 17:20
  • 1
    Are you trying to send an actual email (integration test) or was the intention to mock the sending of the email? Most probably Email is trying to send an email but the proper dependencies have not been configured for the test. – Nkosi Oct 31 '16 at 17:31
  • I'm trying to test if Send method will be called, if right model is given to the controller. I too think that problem is in dependencies that are created during normal application startup. – Cute pumpkin Oct 31 '16 at 17:47

1 Answers1

2

Source: Postal Unit Testing

When unit testing code that uses Postal, you may want to verify that an email would be sent, without actual sending it.

Postal provides an interface IEmailService and an implementation, EmailService, which actually sends email.

Assuming you use some kind of IoC container, configure it to inject an IEmailService into your controller.

Then use the service to send email objects (instead of calling 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);
    }
}

Test this controller by creating a mock of the IEmailService interface.

[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));
    }
}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • Yep, I should have read the documentation better. If someone will use my code and this answer code: var email = EmailSetter.GetEmail(); should be changed to EmailModel email = (new EmailSetter()).GetEmail(); – Cute pumpkin Oct 31 '16 at 18:06
  • 1
    Thought is was a static factory method. fixed. – Nkosi Oct 31 '16 at 18:11