Jim Lobo
Jim Lobo

Reputation: 491

How to Unit test WEB API Controller Exception using Moq

How to Unit test IHttpActionResult Exception InternalServerError with status code 500 and message

[HttpGet]
public async Task<IHttpActionResult> Get(Guid myId)
{
    try
    {
        var myaccount = await _myaccountService.GetMyAccount(myId);
        return Ok(myaccount);
    }
    catch (Exception ex)
    {
        return InternalServerError();
    }
}

Did try with Test method

[TestMethod]
public async Task GeMyAccount_WhenThrowsException_ReturnsServerError()
{
    // Arrange         
    var exception = new Exception("Internal Server Error");
    var expectedResult = new List<MyAccount>
    {
        new  MyAccount
        {
            Id = "1",
            Name = "Name1"
        },
        new  MyAccount
        {
            Id = "2",
            Name = "Name2"
        },
    };
    var myId = new Guid();

    //Act 
    var mockMyAccountService = new Mock<IMyAccountService>();
    mockMyAccountService.Setup(mock => 
    mock.GetMyAccount(myId)).Throws(exception).Verifiable();   
    var controller = new MyAccountController(mockMyAccountService.Object);

    //Assert
    var actualResult = (await controller.Get(myId) as 
    OkNegotiatedContentResult<MyAccount>).Content;       
       ?? var result = actualResult as ObjectResult;
       ?? Assert.AreEqual(StatusCodes.Status500InternalServerError, result.StatusCode);
       ?? Assert.AreEqual("Internal Server Error ", result.Value);
      mockMyAccountService.Verify(b => b.GetMyAccount(myId));
}

Not sure how to get the Exception and status code 500 using Moq.

Upvotes: 2

Views: 1835

Answers (2)

Peter Csala
Peter Csala

Reputation: 22849

As it was said by Nkosi the exception is swallowed by the try-catch block so you are not able to make any assertion against the exception.

But you can (and should) make assertion against the returned object.

[TestMethod]
public async Task GivenAFaultyMyAccountService_WhenICallGet_ThenItReturnsAnInternalServerError()
{
    //Arrange         
    var expectedException = new Exception("Something went wrong");
    var mockMyAccountService = new Mock<IMyAccountService>();
    
    mockMyAccountService
       .Setup(svc => svc.GetMyAccount(It.IsAny<Guid>()))
       .Throws(expectedException);   
    
    var sut = new MyAccountController(mockMyAccountService.Object);

    //Act 
    var actualResult = await sut.Get(Guid.NewGuid());

    //Assert
    Assert.IsInstanceOfType(actualResult, typeof(InternalServerErrorResult));
}

I've made the following changes to your test:

  • I've renamed your test to align with the Given-When-Then structure
  • In this test case I'm only focusing on a single situation when the underlying dependency is malfunctioning, so I've get rid of everything which is related to the happy path
    • The happy path should have a separate test case
  • I've made the mock Setup more generic by replacing the myId parameter to It.IsAny<Guid>()
  • I've also replaced the new Guid() to Guid.NewGuid() because the former would create an empty uuid, while the later will generate a new uuid
  • I've removed the Verifiable call because it is not really needed here
  • The Act phase is when you make the actual call against a given method, not when you are constructing the controller, so I've moved the comment to the right place
  • I've changed the variable name controller to sut, which stands for the System Under Test
  • I've replaced your hard to read assessment logic to a simple type check

Upvotes: 3

Mehdi Fathipour
Mehdi Fathipour

Reputation: 86

Take a look at this code

    [Fact]
    public async Task Test1()
    {
        //arrange 
        //prepare your data for test

        //act
        async Task action()
        {
            //run your sut action
        }

        //assert
        var exception = await Assert.ThrowsAsync<Exception>(action);
        Assert.Equal("Internal Server Error", exception.Message);
    }

Upvotes: -1

Related Questions