使用Moq和AutoFixture对单元测试API进行Mock HttpResponseMessage

Ven*_*nky 6 c# unit-testing moq autofixture asp.net-web-api2

我正在为现有的Web API 2项目编写单元测试.我正在使用Ploeh AutofixtureMoq.

测试方法: 更新

 [Test]
    public async Task Service1_TestMethod() {

      //some code here
     var fakeemail = FakeBuilder.Create<string>("test1234@test.com");
      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( /*   */);

}
Run Code Online (Sandbox Code Playgroud)

Service1方法:

   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.  

   }
Run Code Online (Sandbox Code Playgroud)

如果我评论Service2.AddUser电话,那么一切正常.除了这个调用之外,该方法中还有很多代码.我只有这个电话有问题.如果此调用返回模拟,HttpResponseMessage则一切正常.

Service2是一个外部API.我只是想知道如何mock HttpResponseMessage.任何帮助表示赞赏.

Enr*_*lio 10

您创建的存根:

service2.Setup(i => i.AddUser(fakeUserInvite, fakeUserToken))
        .ReturnsAsync(fakeHttpResponseMessage);
Run Code Online (Sandbox Code Playgroud)

需要用精确的进行实际调用相同的对象,通过引用的那些fakeUserInvite并且fakeUserToken为了起订量返回fakeHttpResponseMessage.

这是因为Moq的参数匹配验证了存根中指定的参数与实际调用中的参数相等.如果不是,则存根将不匹配,并且Moq将返回方法的返回类型的默认值 - 在这种情况下,null因为HttpResponseMessage它是引用类型.

要解决此问题,您可以确保将fakeUserInvitefakeUserToken引用传递给实际service2.AddUser调用,也可以使用稍微不太具体的参数约束.

这是一个例子:

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

这里我们说明AddUser应该使用以下方法调用该方法:

  1. UserInvite对象,其EmailAddressUsername属性具有相同的值fakeEmail作为第一个参数
  2. fakeUserToken第二个参数相同的值

如果这些参数的实际值对您的特定测试场景无关紧要,您可以告诉Moq 始终返回,fakeHttpResponseMessage无论AddUser调用什么参数,都说:

service2.Setup(i => i.AddUser(
            It.IsAny<UserInvite>(),
            It.IsAny<string>()))
        .ReturnsAsync(fakeHttpResponseMessage);
Run Code Online (Sandbox Code Playgroud)