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

4

在启动期间,我基本上会像这样添加一个 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
}

以下是 MyFakeClientPost方法的主体代码:

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 和存根委托处理程序将其运行成功。在存根处理程序中,我传递了一个自定义标头,以便能够从响应中读取重试计数。重试计数实际上是处理程序上的一个属性,每次调用时都会增加,因此它是第一次尝试加上所有后续重试的次数。这意味着如果重试计数为 3,则您应该期望值为 4。

也许你可以使用Testserver类在内存中创建一个完整的运行Web应用程序,并针对它进行真实的HTTP请求测试? - Danny Schneider
1个回答

2
事实是你无法真正地对此进行单元测试:
  1. 重试是通过 DI 在 HttpClient 的顶部注册的。当你进行单元测试时,你不依赖于 DI 而是依赖于单独的组件。因此,集成测试可能更适合这种情况。我已经 详细说明了如何通过 WireMock.Net 进行集成测试。基本思路是创建一个本地 http 服务器(模拟下游系统)并预定义响应序列。
  2. 在定义了重试策略(包括重试次数时间惩罚)之后,你很难轻松地检索它们。因此,从单元测试的角度来看,确保策略已正确定义(例如,延迟以秒为单位而不是分钟)非常困难。我已经为此创建了一个 Github 问题, 但不幸的是新版本的开发已经停滞了。

1
谢谢Peter。我慢慢地得出了这个结论。从集成测试的角度来看,我会看看我能做些什么。 - sr28

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接