【问题标题】:Test Polly retry polly configured via Startup.ConfigureServices() with ASP.NET Core API测试 Polly 重试通过 Startup.ConfigureServices() 使用 ASP.NET Core API 配置的 polly
【发布时间】:2019-01-06 15:49:40
【问题描述】:

我想了解如何测试通过 Startup.ConfigureServices() 配置的 Polly retry polly。

配置服务

Polly 策略在其中配置

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
                 services.AddHttpClient<IHttpClientService, HttpClientService>()
                .SetWaitAndRetryPolicy1();     

     }
}

以下是 Polly 政策:

 public static class IServiceCollectionExtension
    {

    public static void SetWaitAndRetryPolicy1(this IHttpClientBuilder clientBuilder)
        {
                             clientBuilder.AddPolicyHandler((service, request) =>
                            HttpPolicyExtensions.HandleTransientHttpError()
                                .WaitAndRetryAsync(3,
                                    retryCount => TimeSpan.FromSeconds(Math.Pow(2, retryCount)),
                onRetry: (outcome, timespan, retryCount, context) =>
                                {
                                    service.GetService<ILog>().Error("Delaying for {delay}ms, then making retry {retry}.",
                                        timespan.TotalMilliseconds, retryCount);
                                }
                            )

                        );        
        }
    }

以下是我尝试过的:

集成测试

Polly 策略在测试中配置。

  public class RetryPolicyTests : IClassFixture<WebApplicationFactory<Startup>>
    {
        private readonly WebApplicationFactory<Startup> _factory;

        public RetryPolicyTests(WebApplicationFactory<Startup> factory)
        {
            _factory = factory;
        }

        [Theory]
        [InlineData("http://localhost:1234/api/v1/car/")]
        public async Task Test3(string url)
        {
            // Arrange
            var client = _factory.WithWebHostBuilder(whb =>
                {
                    whb.ConfigureServices((bc, sc) =>
                    {
                        sc.AddOptions();
                        sc.AddHttpClient("test")
                          .SetWaitAndRetryPolicy1();         //Test the Polly policy             
                        sc.BuildServiceProvider();
                    });
                })
                .CreateClient();  //cannot get a named or typed HttpClient

            // Act           
            var body = "{}";
            using (var content = new StringContent(body, Encoding.UTF8, "application/json"))
            {

                var response = await client.PostAsync(url, content);



            }

            //Assert: somewhy assert it
        }
    }
}

问题

我无法检索已使用 Polly polly 配置的 HttpClient。因为WebApplicationFactory.CreateClient() 没有返回命名或类型化HttpClient 的重载:

有什么想法吗?

有没有更好的测试方法?

ASPS.NET Core API 2.2

【问题讨论】:

    标签: c# asp.net-core .net-core asp.net-core-webapi polly


    【解决方案1】:

    要最小限度地修改您发布的代码以获取在 HttpClientFactory 上配置的命名或类型 HttpClient,请构建 IServiceProvider,获取 IHttpClientFactory,然后从 IHttpClientFactory 获取配置的客户端。

    var configuredClient = sc.BuildServiceProvider()
        .GetRequiredService<IHttpClientFactory>()
        .CreateClient("test");
    

    许多人认为像这样使用IServiceProvider 是生产代码中的服务定位器反模式;也许在测试中可以将要进行单元测试的特定项目从默认应用程序配置中提取出来。但是,也有更短的方法可以让测试获得在 HttpClientFactory 上配置的示例 HttpClient,而无需使用完整的 WebApplicationFactory(请参阅答案的最后部分)。


    对于完整的端到端集成测试,测试您的应用如何使用配置的策略,使用WebApplicationFactory 来运行您的应用的某些端点,例如http://localhost:1234/api/v1/car/

    您可以 - 在集成测试中 - 使用 Mountebank for .NETHttpClientInterception 之类的工具来存根配置的 HttpClient 进行的调用,以便这些调用返回您期望策略处理的错误。

    您可以使用WebHostBuilder.ConfigureServices(...) 的功能来修改应用程序的正常启动,以便轻松断言某些内容以证明已调用该策略。例如,您可以配置模拟/假 ILog 实现,并断言在您的 onRetry 委托中调用 ILog.Error(...)


    对于在 HttpClientFactory 上的给定 HttpClient 配置上配置的 Polly 策略的最短可能、自包含单元测试,您可以使用如下代码模式。这仅使用 IHttpClientFactory 和标准的 Microsoft DI 基础结构;没有来自 ASP.NET 的网络主机。

    public class HttpClientFactory_Polly_Policy_Test
    {
        [Fact]
        public async Task Given_a_retry_policy_configured_on_a_named_client_When_call_via_the_named_client_Then_the_policy_is_used()
        {
            // Given / Arrange 
            IServiceCollection services = new ServiceCollection();
    
            bool retryCalled = false;
    
            HttpStatusCode codeHandledByPolicy = HttpStatusCode.InternalServerError;
    
            const string TestClient = "TestClient";
            services.AddHttpClient(TestClient)
                .AddPolicyHandler(HttpPolicyExtensions.HandleTransientHttpError()
                    .RetryAsync(3, onRetry: (_, __) => retryCalled = true))
                .AddHttpMessageHandler(() => new StubDelegatingHandler(codeHandledByPolicy));
    
            HttpClient configuredClient =
                services
                    .BuildServiceProvider()
                    .GetRequiredService<IHttpClientFactory>()
                    .CreateClient(TestClient);
    
            // When / Act
            var result = await configuredClient.GetAsync("https://www.doesnotmatterwhatthisis.com/");
    
            // Then / Assert
            Assert.Equal(codeHandledByPolicy, result.StatusCode);
            Assert.True(retryCalled);
        }
    
    }
    
    public class StubDelegatingHandler : DelegatingHandler
    {
        private readonly HttpStatusCode stubHttpStatusCode;
        public StubDelegatingHandler(HttpStatusCode stubHttpStatusCode) => this.stubHttpStatusCode = stubHttpStatusCode;
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) => Task.FromResult(new HttpResponseMessage(stubHttpStatusCode));
    }
    

    如果将策略声明提取到方法中(例如您发布的代码中的SetWaitAndRetryPolicy1()),则上述方法提供了一种更注重单元测试的方法来测试它们。

    【讨论】:

    猜你喜欢
    • 2022-07-25
    • 2022-07-14
    • 1970-01-01
    • 1970-01-01
    • 2019-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多