Peter
Peter

Reputation: 5342

How do I setup a mock that returns IHttpActionResult?

I'm using VisualStudio 2015, .NET 4.6, Moq 4.5.2, Nunit 3.4.1 to test a WebApi2 Controller. However, I am getting a null response object when mocking the intended controller method:

var response = actionResult as NegotiatedContentResult;

I am guessing I must be setting up my mock of the UserService incorrectly?

My suspicion is that this part is the culprit:

userServiceMock.Setup(service => service.InsertOrUpdateUser( It.IsAny())).Returns(1);

As I am getting the following in the output window:

'((System.Web.Http.Results.OkNegotiatedContentResult)actionResult).Request' threw an exception of type 'System.InvalidOperationException'

Is the problem that I am telling Moq to expect a return value of 1, but the Put method returns OkNegotiatedContentResult?

My questions are (possibly the same question):

1) Am I setting up my Moq correctly and

2) how do I resolve the problem so my response object is populated?

Thanks much.

Here is the Test method:

[Test]
public void Put_ShouldUpdate_User()
{
    // Arrange
    var userServiceMock = new Mock<IUserService>();

    userServiceMock.Setup(service => service.InsertOrUpdateUser(
        It.IsAny<User>())).Returns(1);

    var controller = new UsersController(userServiceMock.Object);

    // Act
    IHttpActionResult actionResult = controller.Put(

        new User()
        {
            Id = 1,
            Name = "Joe"
        });

    var response = actionResult as NegotiatedContentResult<User>;

    // Assert:
    Assert.IsNotNull(response);
    var newUser = response.Content;
    Assert.AreEqual(1, newUser.Id);
    Assert.AreEqual("Joe", newUser.Name);
}

Here is the UserController method:

// PUT api/users/1
public IHttpActionResult Put(User user)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    return Ok(_userService.InsertOrUpdateUser(user));

}

Finally, the method for the UserService:

public int InsertOrUpdateUser(User user)
{
    return _userRepository.InsertOrUpdateUser(user);
}

Upvotes: 1

Views: 3306

Answers (1)

Nkosi
Nkosi

Reputation: 247631

According to your code IUserService has

public interface IUserService {

    int InsertOrUpdateUser(User user);

}

which returns an int.

If you do the following in your controller

return Ok(_userService.InsertOrUpdateUser(user));

then based on the interface and your setup mock, that will return a response type of OkNegotiatedContentResult<int>. But in your test you do this

var response = actionResult as NegotiatedContentResult<User>;

where you cast your returned result as NegotiatedContentResult<User> this will cause Assert.IsNotNull(response); to fail as the cast will result in response being null.

Given the asserts of your test then you would have to update your controller's Put method to return the User user after the mocked action like so...

public IHttpActionResult Put(User user) {
    if (!ModelState.IsValid) {
        return BadRequest(ModelState);
    }
    var count = _userService.InsertOrUpdateUser(user);
    if(count == 1)
        return Ok(user);
    else
        return BadRequest(); // 500 (Internal Server Error) you choose. 
}

and also update the test as follows

//...other code removed for brevity

var response = actionResult as OkNegotiatedContentResult<User>;

// Assert:
Assert.IsNotNull(response);
var newUser = response.Content;
Assert.AreEqual(1, newUser.Id);
Assert.AreEqual("Joe", newUser.Name);

Upvotes: 1

Related Questions