如何模拟httpclient

3

我刚开始学习TDD,你能否使用Moq编写测试用例来测试以下代码:

public async Task<Model> GetAssetDeliveryRecordForId(string id)
{
    var response = await client.GetAsync($"api/getdata?id={id}");
    response.EnsureSuccessStatusCode();
    var result = await response.Content.ReadAsAsync<Model>();
    return result;
}

感谢您的提前帮助。

你能试着独立进行一些研究和编写单元测试,如果遇到任何问题,请在这里提问吗? - Chetan
1个回答

16

您可以使用Moq进行模拟。

使用Moq来为您完成此操作

现在,您可能不想为每个响应创建一个新类。 您可以编写测试帮助程序类,该类可以为测试准备各种响应,但这可能不够灵活。

Moq是一款流行的.NET库,可帮助进行测试对象的模拟。 实质上,它使用反射和表达式在运行时动态生成模拟,根据您使用流畅API声明的规范。

现在,这里稍微有些问题。正如您注意到的那样,抽象的HttpMessageHandler类上的SendAsync方法是受保护的。 注意事项:Moq无法像处理接口或公共方法那样轻松自动实现受保护的方法。原因是流畅 API 在模拟类型上使用表达式,而这不能提供私有或受保护的成员,因为从外部访问类。 因此,我们必须使用Moq的一些高级功能来模拟受保护方法。

因此,Moq具有用于此的API。您可以在using子句中使用Moq.Protected;,然后可以继续使用.Protected()方法来处理Moq。这为您提供了一些其他方法,您可以使用它们来访问受保护成员的名称。

使用HttpClient的类的完整测试如下:

// ARRANGE
var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);
handlerMock
   .Protected()
   // Setup the PROTECTED method to mock
   .Setup<Task<HttpResponseMessage>>(
      "SendAsync",
      ItExpr.IsAny<HttpRequestMessage>(),
      ItExpr.IsAny<CancellationToken>()
   )
   // prepare the expected response of the mocked http call
   .ReturnsAsync(new HttpResponseMessage()
   {
      StatusCode = HttpStatusCode.OK,
      Content = new StringContent("[{'id':1,'value':'1'}]"),
   })
   .Verifiable();

// use real http client with mocked handler here
var httpClient = new HttpClient(handlerMock.Object)
{
   BaseAddress = new Uri("http://test.com/"),
};

var subjectUnderTest = new MyTestClass(httpClient);

// ACT
var result = await subjectUnderTest
   .GetSomethingRemoteAsync('api/test/whatever');

// ASSERT
result.Should().NotBeNull(); // this is fluent assertions here...
result.Id.Should().Be(1);

// also check the 'http' call was like we expected it
var expectedUri = new Uri("http://test.com/api/test/whatever");

handlerMock.Protected().Verify(
   "SendAsync",
   Times.Exactly(1), // we expected a single external request
   ItExpr.Is<HttpRequestMessage>(req =>
      req.Method == HttpMethod.Get  // we expected a GET request
      && req.RequestUri == expectedUri // to this uri
   ),
   ItExpr.IsAny<CancellationToken>()
);
对于单元测试,不要模拟 HttpClient。相反,您应该模拟 HttpMessageHandler,将其放入 HttpClient 中,并以此方式返回任何您想要的内容。如果您不想为每个测试创建一个特定的 HttpMessageHandler 派生类,您还可以让 Moq 自动为您创建模拟对象。
阅读整篇文章请点击这里

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接