我正在寻找一些在 Asp.net core 应用程序的集成测试中模拟 Typed HttpClient 的想法。
假设我有一个带有注册的 Typed HttpClient 的服务集合,如下所示
var serviceCollection = new ServiceCollection();
serviceCollection.AddHttpClient<ITestApiClient, TestApiClient>();
var services = serviceCollection.BuildServiceProvider();
Run Code Online (Sandbox Code Playgroud)
和TestApiClient这样的定义
public class TestApiClient: ITestApiClient
{
HttpClient _httpClient;
public TestApiClient(HttpClient httpClient)
{
_httpClient = httpClient;
}
public void MakeTestApiCall()
{
var response = _httpClient.GetAsync("https://reqres.in/api/users?page=2");
response.Result.Content.ReadAsStringAsync().Result.Dump();
}
}
Run Code Online (Sandbox Code Playgroud)
我正在寻找一种方法,将模拟HttpClient实现注入到TestApiClient使用 ServiceCollection 中,而无需直接实例化TestApiClient。
类似于我们在下面的集成测试中如何用模拟的 Foo 实现替换真实的 Foo 实现。
var fooMock = new Mock<IFoo>();
services.AddSingleton(fooMock);
Run Code Online (Sandbox Code Playgroud)
请注意,我已经找到了一种使用 Moq 和RichardSzalay.MockHttp. 我的问题是如何替换 ServiceCollection 中类型化的 Httpclient(模拟 HttpClientFactory?)。
以下是我如何解决在 aspnet core 6 集成测试中模拟 HttpClient 的问题:
我为集成测试创建了一个自定义 WebApplicationFactory,其中使用模拟的 HttpMessageHandler 将 HttpClient 服务替换为新客户端。
internal class CustomWebApplicationFactory : WebApplicationFactory<Program>
{
public Mock<HttpMessageHandler> handlerMock { get; private set; }
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
// Remove existing IHttpClientFactory and HttpClient
var httpClientFactoryDescriptor = services.SingleOrDefault(d => d.ServiceType ==
typeof(IHttpClientFactory));
services.Remove(httpClientFactoryDescriptor);
var httpClientDescriptor = services.SingleOrDefault(d => d.ServiceType ==
typeof(HttpClient));
services.Remove(httpClientDescriptor);
// Create a mock HttpMessageHandler
this.handlerMock = new Mock<HttpMessageHandler>();
// Create an HttpClient using the mocked handler
var client = new HttpClient(this.handlerMock.Object);
var clientFactoryMock = new Mock<IHttpClientFactory>();
clientFactoryMock
.Setup(f => f.CreateClient(It.IsAny<string>()))
.Returns(client);
// Add the new HttpClient as singleton
services.AddSingleton<IHttpClientFactory>(clientFactoryMock.Object);
services.AddSingleton<HttpClient>(client);
});
}
}
Run Code Online (Sandbox Code Playgroud)
模拟的 HttpMessageHandler 作为公共属性公开,可供测试类访问,我可以在其中进行设置:
[Fact]
public async Task CallApiTest()
{
// Arrange
var factory = new CustomWebApplicationFactory();
var client = factory.CreateClient();
factory.handlerMock
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.Is<HttpRequestMessage>(r => r.Method == HttpMethod.Get),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent("[]")
});
// Act
var result = await client.GetAsync("/callApi");
// Assert
result.StatusCode.Should().Be(HttpStatusCode.OK);
}
Run Code Online (Sandbox Code Playgroud)