【问题标题】:How can I test a Polly retry policy that's set during startup?如何测试启动期间设置的 Polly 重试策略?
【发布时间】:2021-12-02 16:47:03
【问题描述】:

在启动过程中,我基本上添加了一个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。目前,这会创建正确的客户端并触发帖子。它会抛出HttpResponseException,但这样做会退出测试而不是使用重试策略。

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

更新

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

【问题讨论】:

  • 也许您可以使用 Testserver 类在内存中创建一个完整的正在运行的 Web 应用程序并使用真实的 http 请求对其进行测试?

标签: c# unit-testing httpclient polly


【解决方案1】:

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

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

【讨论】:

  • 谢谢彼得。我慢慢得出了这个结论。我会从集成测试的角度看看我能做什么
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-10-19
  • 1970-01-01
  • 1970-01-01
  • 2016-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多