c# - 在 Xunit 测试中使用 Moq 库模拟 HttpClient GetAsync
问题描述
我正在为这个简单地调用外部 API 的小服务编写一个简单的单元测试:
public class ApiCaller : IApiCaller
{
private readonly IHttpClientFactory _httpFactory;
public ApiCaller(IHttpClientFactory httpFactory)
{
_httpFactory = httpFactory;
}
public async Task<T> GetResponseAsync<T>(Uri url)
{
using (HttpClient client = _httpFactory.CreateClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.Timeout = TimeSpan.FromSeconds(20);
using (HttpResponseMessage response = await client.GetAsync(url))
{
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(responseBody);
}
}
}
}
我的第一个问题是:模拟并因此测试此类服务似乎不是很常见的做法,我想知道是否有一些具体的解释。
其次,我尝试编写一个简单的单元测试,但我无法模拟GetAsync调用,因为 HttpClient 没有实现任何接口。
public class ApiCallerTest
{
private readonly ApiCaller _target;
private readonly Mock<IHttpClientFactory> _httpClientFactory;
public ApiCallerTest()
{
_httpClientFactory = new Mock<IHttpClientFactory>();
_target = new ApiCaller(_httpClientFactory.Object);
}
[Fact]
public void WhenACorrectUrlIsProvided_ServiceShouldReturn()
{
var client = new HttpClient();
_httpClientFactory.Setup(x => x.CreateClient(It.IsAny<string>())).Returns(client);
var httpMessageHandler = new Mock<HttpMessageHandler>();
}
}
解决方案
无论您使用的 HttpClient 类中的方法是什么(GetAsync、PostAsync 等),下面的代码都是您应该使用的。所有这些方法都是为了方便程序员而创建的。他们所做的是使用 HttpMessageHandler 类的SendAsync方法。
var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
// Setup Protected method on HttpMessageHandler mock.
mockHttpMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>()
)
.ReturnsAsync((HttpRequestMessage request, CancellationToken token) =>
{
HttpResponseMessage response = new HttpResponseMessage();
// configure your response here
return response;
});
然后你以这种方式使用它:
var httpClient = new HttpClient(mockHttpMessageHandler.Object);
var result = await httpClient.GetAsync(url, cancellationToken);
您也可以在这里查看如何为 httpclient getasync 方法创建模拟?
推荐阅读
- php - Composer 在没有明确原因的情况下更新失败
- r - 如何解决solve.default(H,g [!fixed])中的mlogit错误:系统在计算上是奇异的:倒数条件数= 3.03549e-18?
- android - BottomSheetBehavior Android 中所有状态详解
- asp.net - Blazor WebAssembly:不支持提供的 ContentType;
- python - 如何使用 Python 中的请求发布带有列表的字典?
- javascript - 为什么我的倒计时时钟停止计数?
- r - IV回归计算
- java - 尽管在 Firebase 数据库中有值,但调试器显示空值
- oracle - PL/SQL UTL_HTTP 发送多个原始数据
- spring-boot - 在 Spring Boot 应用程序中验证 Azure 令牌