You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 00:24:04