如何模拟httpclient

Sat*_*kla -2 c# nunit moq .net-core

我是 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;
}
Run Code Online (Sandbox Code Playgroud)

提前致谢。

Ali*_*ami 6

你可以用Moq它来模拟它。

使用 Moq 为您做到这一点

现在,您可能不想为每个响应创建一个新类。你可以为测试编写一个辅助类,你可以用你想要的任何响应来准备它,但这可能不够灵活。

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

现在,这里也有一个小问题。正如您所注意到的,抽象 HttpMessageHandler 类上的 SendAsync 方法是受保护的。警告:Moq 不能像使用接口或公共方法那样轻松地自动实现受保护的方法。原因是,流畅的 API 在模拟类型上使用表达式,并且当您从这里外部访问类时,这不能提供私有或受保护的成员。因此,我们必须使用 Moq 的一些更高级的功能来模拟我们的受保护方法。

因此,Moq 有一个 API。你确实使用最小起订量。受保护;在您的 using 子句中,然后您可以使用 .Protected() 方法继续您的 Moq。这为您提供了一些关于 Moq 的额外方法,您可以在其中使用他们的名字访问受保护的成员。

使用 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>()
);
Run Code Online (Sandbox Code Playgroud)

对于单元测试,您不要模拟 HttpClient。相反,您模拟 HttpMessageHandler,将其放入 HttpClient 并让它以您想要的方式返回任何内容。如果您不想为每个测试创建 HttpMessageHandler 的特定派生,您还可以让 Moq 自动为您创建模拟。

此处阅读整篇文章。