我正在寻找一些在 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)
        |   归档时间:  |  
           
  |  
        
|   查看次数:  |  
           1776 次  |  
        
|   最近记录:  |