使用 Moq 和 AutoFixture 进行单元测试时模拟 HttpResponseMessage API

Mock HttpResponseMessage while unit testing API with Moq and AutoFixture

我正在为现有的 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( /*   */);

}

服务 1 方法:

   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.  

   }

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

Service2 是一个外部 API。我只是想知道如何 mock HttpResponseMessage。感谢您的帮助。

您创建的存根:

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

要求使用与 fakeUserInvitefakeUserToken 引用的对象完全 相同的 对象进行实际调用,以便 Moq return fakeHttpResponseMessage.

这是因为 Moq's argument matching 验证存根中指定的参数 等于 实际调用中的参数。如果它们不匹配,存根将不匹配,Moq 将 return 方法的 return 类型的默认值——在本例中为 null 因为 HttpResponseMessage 是引用类型.

要解决此问题,您可以确保将 fakeUserInvitefakeUserToken 引用传递给实际的 service2.AddUser 调用,或者您可以使用不太具体的 argument constraints.

这是一个例子:

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

这里我们声明 AddUser 方法应该被调用:

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

如果这些参数的实际值对您的特定测试场景无关紧要,您可以告诉 Moq always return fakeHttpResponseMessage 无论通过说:

调用什么参数 AddUser
service2.Setup(i => i.AddUser(
            It.IsAny<UserInvite>(),
            It.IsAny<string>()))
        .ReturnsAsync(fakeHttpResponseMessage);