如何测试在启动期间设置的 Polly 重试策略?

How can I test a Polly retry policy that's set during startup?

在启动过程中,我基本上添加了一个 HttpClient 这样的:

services.AddHttpClient<IHttpClient, MyHttpClient>().AddPolicyHandler(GetRetryPolicy());

public IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
    HttpPolicyExtensions
        .HandleTransientHttpError()
        .OrResult(message => message.StatusCode == HttpStatusCode.NotFound)
        .WaitAndRetryAsync(GetBackOffDelay(options),
            onRetry: (result, timespan, retryAttempt, context) =>
            {
                context.GetLogger()?.LogWarning($"Failure with status code {result.Result.StatusCode}. Retry attempt {retryAttempt}. Retrying in {timespan}.");
            }));
}

如何测试重试策略是否按预期工作?我试过写这样的测试:

public async Task MyTest()
{
    var policy = GetMockRetryPolicy(); // returns the policy shown above.
    var content = HttpStatusCode.InternalServerError;
    var services = new ServiceCollection();
    services.AddHttpClient<IHttpClient, MyFakeClient>()
        .AddPolicyHandler(policy);

    var client = (MyFakeClient)services.BuildServiceProvider().GetRequiredService<IHttpClient>();
    await client.Post(new Uri("https://someurl.com")), content);

    // Some asserts that don't work right now
}

这里是我在 MyFakeClient 上的大部分 Post 方法供参考:

if(Enum.TryParse(content.ToString(), out HttpStatusCode statusCode))
{
    if(statusCode == HttpStatusCode.InternalServerError)
    {
        throw new HttpResponseException(new Exception("Internal Server Error"), (int)HttpStatusCode.InternalServerError);
    }
}

MyFakeClient 有一个 Post 方法检查内容是否为 HttpStatusCode,如果是内部服务器错误则抛出 HttpResponseException。目前,这会创建正确的客户端并触发 post 罚款。它抛出 HttpResponseException 但这样做会退出测试而不是使用重试策略。

如何让它在测试中使用重试策略?

更新

我听从了 Peter 的建议,沿着集成测试路线走下去,并设法使用 hostbuilder 和存根委托处理程序让它工作。在存根处理程序中,我传入自定义 header 以使我能够从响应中读回重试计数。重试计数只是处理程序上的一个 属性,每次调用时都会递增,因此它实际上是第一次尝试,加上所有后续重试。这意味着如果重试次数为 3,您应该期望值为 4。

问题是你不能真正对它进行单元测试:

  1. 重试通过 DI 注册在 HttpClient 的顶部。当您进行单元测试时,您不依赖 DI,而是依赖单个组件。因此,集成测试可能更适合这种情况。我已经 。基本思想是创建一个具有预定义响应序列的本地 http 服务器(模拟下游系统)。
  2. 定义重试策略(使用重试计数时间惩罚)后,您将无法轻松检索它们。因此,从单元测试的角度来看,确实很难确保策略已被正确定义(比如延迟以秒为单位指定,而不是以分钟为单位)。我已经创建了一个github issue for that,可惜新版本的开发一直卡住了