Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock HttpResponseMessage while unit testing API with Moq and AutoFixture

I am writing unit tests for the existing Web API 2 project. For which i am using Ploeh Autofixture and Moq.

Test Method : UPDATED

 [Test]
    public async Task Service1_TestMethod() {

      //some code here
     var fakeemail = FakeBuilder.Create<string>("[email protected]");
      var fakeUserInvite =
                FakeBuilder.Build<UserInvite>()
                    .With(i => i.EmailAddress, fakeemail)
                    .With(i => i.Username, fakeemail)
                    .Create();
      var fakeUserToken = FakeBuilder.Create<string>();
      var fakeHttpResponseMessage =
                    Fixture.Build<HttpResponseMessage>()
                                 .With(h => h.StatusCode, HttpStatusCode.OK).Create();
  //Here i am mocking another service method. Whose response is HttpResponseMessage.
  Service2.Setup(i => i.AddUser(fakeUserInvite, fakeUserToken))
            .ReturnsAsync(fakeHttpResponseMessage);

  var result = await Service1.AddUser( /*   */);

}

Service1 Method :

   public async Task<bool> AddUser(/*   */)
   {
    var response = await Service2.AddUser(userInvite, userToken); // response is null even after mocking it.

   // Add user code follows bassed on the above response.  

   }

If i comment the Service2.AddUser call then everything works. There is a lot of code in that method apart from this call. I am having problem with only this call. If this call returns the mocked HttpResponseMessage then everything works.

Service2 is an external API. I am just wondering how to mock HttpResponseMessage. Any help is appreciated.

like image 449
Venky Avatar asked Aug 18 '16 10:08

Venky


1 Answers

The stub you create with:

service2.Setup(i => i.AddUser(fakeUserInvite, fakeUserToken))
        .ReturnsAsync(fakeHttpResponseMessage);

requires the actual call to be made with the exact same objects as the ones referenced by fakeUserInvite and fakeUserToken in order for Moq to return fakeHttpResponseMessage.

This is because Moq's argument matching verifies that the arguments specified in the stub are equal to the ones made in the actual call. If they are not, the stub won't match and Moq will return the default value for the method's return type – in this case null since HttpResponseMessage is a reference type.

To solve this problem, you can either make sure that the fakeUserInvite and fakeUserToken references are being passed to the actual service2.AddUser call or you can use somewhat less specific argument constraints.

Here's an example:

service2.Setup(i => i.AddUser(
            It.Is<UserInvite>(u => u.EmailAddress == fakeEmail &&
                                   u.Username == fakeEmail),
            fakeUserToken))
        .ReturnsAsync(fakeHttpResponseMessage);

Here we're stating that the AddUser method should be called with:

  1. A UserInvite object whose EmailAddress and Username properties have the same value as fakeEmail as the first argument
  2. The same value as fakeUserToken as the second argument

If the actual values of those arguments don't matter to your specific test scenario, you can tell Moq to always return fakeHttpResponseMessage regardless of what arguments AddUser is being called with by saying:

service2.Setup(i => i.AddUser(
            It.IsAny<UserInvite>(),
            It.IsAny<string>()))
        .ReturnsAsync(fakeHttpResponseMessage);
like image 58
Enrico Campidoglio Avatar answered Sep 28 '22 19:09

Enrico Campidoglio