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

如何测试.NET项目启动时注册的Polly重试策略?

问题根因
  1. Polly 针对 HttpClient 注册的策略,仅作用于 HttpClient 内置的请求管道(也就是 HttpClient.SendAsync 方法的执行链路)。你自定义的 MyHttpClient/MyFakeClient 直接在封装的 Post 方法内抛出异常,完全绕开了 Polly 策略的作用范围,策略无法感知到异常,自然不会触发重试。
  2. 你当前的重试策略仅配置了 HandleTransientHttpError(),这个方法默认只处理三类场景:HttpRequestException 类型异常、响应状态码为 5xx、响应状态码为 408(超时),你自定义抛出的 HttpResponseException 不在默认捕获范围内,就算走到策略层也不会触发重试。
调整方案

方案一:单元测试轻量验证(推荐用于策略逻辑单独验证)

直接替换自定义假客户端的实现,改用 DelegatingHandler 模拟接口异常/错误返回,这是官方推荐的 HttpClient 测试方案:

  1. 先实现自定义的存根消息处理器,记录调用次数、模拟返回结果:
public class StubHttpMessageHandler : DelegatingHandler
{
    public int CallCount { get; private set; }
    private readonly HttpStatusCode _returnStatusCode;

    public StubHttpMessageHandler(HttpStatusCode returnStatusCode)
    {
        _returnStatusCode = returnStatusCode;
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        CallCount++;
        // 模拟错误响应,也可以根据需求抛出HttpRequestException
        return Task.FromResult(new HttpResponseMessage(_returnStatusCode)
        {
            RequestMessage = request
        });
    }
}
  1. 调整服务注册和测试逻辑:
public async Task MyTest()
{
    const int retryCount = 3; // 替换为你实际配置的重试次数
    var policy = GetRetryPolicy(); // 取你实际的重试策略实例
    var stubHandler = new StubHttpMessageHandler(HttpStatusCode.InternalServerError);

    var services = new ServiceCollection();
    services.AddHttpClient<IHttpClient, MyHttpClient>()
        .AddPolicyHandler(policy)
        .AddHttpMessageHandler(() => stubHandler); // 注入存根处理器替换真实请求逻辑

    var serviceProvider = services.BuildServiceProvider();
    var client = serviceProvider.GetRequiredService<IHttpClient>();
    
    // 执行请求
    _ = await client.Post(new Uri("https://someurl.com"), new StringContent("test"));

    // 断言:总调用次数 = 首次请求 + 重试次数
    Assert.Equal(retryCount + 1, stubHandler.CallCount);
}
  1. 如果业务逻辑确实需要处理自定义的 HttpResponseException,可以在重试策略里新增异常捕获规则:
public IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        // 新增捕获自定义的HttpResponseException
        .Or<HttpResponseException>()
        .OrResult(message => message.StatusCode == HttpStatusCode.NotFound)
        .WaitAndRetryAsync(GetBackOffDelay(options),
            onRetry: (result, timespan, retryAttempt, context) =>
            {
                var statusCode = (result.Exception as HttpResponseException)?.StatusCode ?? result.Result?.StatusCode;
                context.GetLogger()?.LogWarning($"Failure with status code {statusCode}. Retry attempt {retryAttempt}. Retrying in {timespan}.");
            });
}

方案二:集成测试验证(就是你补充提到的方案)

通过 IHostBuilder 构建完整的服务栈测试,逻辑和单元测试方案类似,只是更贴近真实运行环境:

  • 注册存根 DelegatingHandler 替换真实的请求发送逻辑
  • 在处理器内记录调用次数,或者在响应头写入重试计数做断言
  • 3次重试配置下总调用次数为4是正确逻辑,符合预期

内容的提问来源于stack exchange,提问作者sr28

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 02:15:03