Help123
Help123

Reputation: 1443

Asp.net core 2 XUnit -- Unit Test MVC controller that throws exception

I am trying to unit test a controller that returns an IActionResult but can also throw an exception in certain circumstances. The problem I am running into is I'm not sure how to call it as the Assert throws an error where you cannot convert from IActionResult to Action.

How would I go about testing below statement?

 Assert.Throws<Exception>(await controller.SendEmail(email)); //how to test this

I looked through the Microsoft testing controller documentation and didn't find something relevant. Most examples I see testing exceptions are for things like accessing repositories or services.

I understand I can return a badrequest or redirect to the page with an error message. But is what I am trying to accomplish possible?

My HomeController Method

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> SendEmail(EmailModel emailModel)
        {
            if(!ModelState.IsValid)
            {
                return View("Index",emailModel);
            }

            var response = await _sendEmail.SendEmailMessage(emailModel);

            if (response != System.Net.HttpStatusCode.Accepted)
            {
                throw new Exception("Email failed to send, please try again later");
            }
            else
            {
                TempData["message"] = $"Email has been sent";
            }

            return RedirectToAction("Index");
        }

XUnit HomeControllerTest Constructor for arrange

        private Mock<ISendEmail> mockSendEmail;
        private HomeController controller;

        public HomeControllerShould()
        {
            mockSendEmail = new Mock<ISendEmail>();
            mockSendEmail.Setup(x => x.SendEmailMessage(It.IsAny<EmailModel>())).ReturnsAsync(HttpStatusCode.Accepted);
            controller = new HomeController(mockSendEmail.Object);
        }

XUnit Test for Sending Email

 [Fact]
    public async Task SendEmailActionThrowsExceptionOnEmailFailure()
    {
        mockSendEmail.Setup(x => x.SendEmailMessage(It.IsAny<EmailModel>())).ReturnsAsync(HttpStatusCode.InternalServerError);
        var email = new EmailModel();

        Assert.Throws<Exception>(await controller.SendEmail(email)); //how to test this
    }

Upvotes: 0

Views: 1590

Answers (1)

Win
Win

Reputation: 62260

Assert.Throws requires a function. You could use ThrowsAsync.

[Fact]
public async Task SendEmailActionThrowsExceptionOnEmailFailure()
{
    mockSendEmail.Setup(x => x.SendEmailMessage(It.IsAny<EmailModel>()))
        .ReturnsAsync(HttpStatusCode.InternalServerError);

    var email = new EmailModel();

     await Assert.ThrowsAsync<Exception>(() => controller.SendEmail(email)); 
}

FYI: We don't normally return HttpStatusCode from service layer such as email service, but I'll let you decide.

Upvotes: 2

Related Questions