Mock HttpResponseMessage while unit testing API with Moq and AutoFixture
Asked Answered
P

1

6

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.

Puklich answered 18/8, 2016 at 10:21 Comment(9)
Are you getting any exception? If yes, which one?Madra
No exception. Just the response is null for the call Service2.AddUser. I want the response to be the object fakeHttpResponseMessage which i mocked while setup the call.Puklich
How are fakeUserInvite and fakeUserToken being passed to the Service2.AddUser method? The actual call being made needs to use those same objects in order for Moq to return your fakeHttpResponseMessage. See matching arguments in the Moq documentation.Madra
Those 2 parameters are created by AutoFixture and passed to Service2.AddUser. Those 2 parameters are valid types otherwise Service2.Setup will throw compile time error. Updating question with these objects creation.Puklich
Is Service2.AddUser a static method? If not, how is the Service2 test double being passed to Service1?Madra
Service2.AddUser is not a static method. Service2 is a Mock of original Service2, which is injected to Service1 through Unity.Puklich
Service2 has other methods which return types other than HttpResponseMessage. They are working fine. Only AddUser method is giving problem as it is returning HttpResponseMessage. I think there is something tricky in mocking HttpResponseMessagePuklich
Let us continue this discussion in chat.Puklich
Please proved a minimal reproducible example so others can reproduce and understand the problem to provide better assistance.Yenyenisei
M
10

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);
Madra answered 18/8, 2016 at 11:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.