.NET Core中如何用Moq Mock结合Polly策略的IHttpClientFactory生成的HttpClient
解决方案
核心思路
- 你通过
IHttpClientFactory注册的Polly策略是嵌入在HttpClient的请求管道中的,不能直接Mock HttpClient本身,否则会跳过整个管道导致策略失效 - 正确做法是保留原有的服务注册逻辑,仅替换HttpClient最内层负责实际发请求的
HttpMessageHandler为Mock对象,这样请求会完整经过Polly策略层,再走到Mock的Handler返回模拟响应,保证策略按配置生效
前置依赖
除项目原有依赖外,测试项目需要安装Nuget包:Moq
具体实现代码
using Moq; using Moq.Protected; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.DependencyInjection; using System.Net; using System.Net.Http.Headers; // 1. 创建Mock的HttpMessageHandler var mockHttpHandler = new Mock<HttpMessageHandler>(); // 2. 配置模拟的HTTP响应,示例:前2次请求返回500,第3次返回200,用来测试重试策略 int requestCount = 0; mockHttpHandler.Protected() .Setup<Task<HttpResponseMessage>>( "SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>() ) .ReturnsAsync(() => { requestCount++; if (requestCount <= 2) { return new HttpResponseMessage(HttpStatusCode.InternalServerError); } return new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("{\"code\":0,\"msg\":\"success\"}") }; }) .Verifiable(); // 3. 复用原有服务注册逻辑,仅替换HttpClient的主Handler为Mock对象 IHost host = new HostBuilder() .ConfigureServices((hostingContext, services) => { services.AddHttpClient("TestClient", client => { client.DefaultRequestHeaders.Add("Authorization", $"Bearer {accessToken}"); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); }) .AddPolicyHandler(PollyPolicies.HttpResponsePolicies( arg1, arg2, arg3)) // 关键:替换默认的HttpMessageHandler为Mock对象 .ConfigurePrimaryHttpMessageHandler(() => mockHttpHandler.Object); }) .Build(); // 4. 获取HttpClient发起请求 IHttpClientFactory httpClientFactory = host.Services.GetRequiredService<IHttpClientFactory>(); HttpClient httpClient = httpClientFactory.CreateClient("TestClient"); var response = await httpClient.GetAsync("https://test-api.com/endpoint"); // 5. 验证Polly策略是否生效,示例:配置2次重试的场景下,SendAsync应该被调用3次(首次+2次重试) mockHttpHandler.Protected().Verify( "SendAsync", Times.Exactly(3), ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>() );
常见避坑说明
- 不要直接Mock
IHttpClientFactory返回手动新建的HttpClient,手动构造的HttpClient没有绑定你注册的Polly管道,会导致策略完全不生效 - 如果需要模拟超时、请求取消等场景,可在
ReturnsAsync中抛出TaskCanceledException等对应异常即可,Polly的超时、熔断策略会正常捕获处理
内容的提问来源于stack exchange,提问作者qvt
相关产品推荐
相关产品推荐

