Тест Polly, повтор попыток, настроенный через Startup.ConfigureServices () с ASP.NET Core API - PullRequest
0 голосов
/ 04 января 2019

Я хочу узнать, как можно протестировать Polly Retry, настроенную с помощью Startup.ConfigureServices ().

ConfigureServices

Политика Polly в ней настроена

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

     }
}

Ниже приведена политика Полли:

 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);
                                }
                            )

                        );        
        }
    }

Ниже я попробовал:

Интеграционный тест

ПоллиПолитика настроена в рамках теста.

  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
        }
    }
}

Проблема заключается в том, что

Я не могу получить HttpClient, настроенный с помощью Polly Polly.Потому что WebApplicationFactory.CreateClient() не имеет перегрузок, которые возвращают именованный или типизированный HttpClient:

Есть идеи?

Есть ли лучший способ проверить это?

ASPS.NETCore API 2.2

1 Ответ

0 голосов
/ 05 января 2019

Чтобы минимально изменить опубликованный код для получения именованного или напечатанного HttpClient, настроенного в HttpClientFactory, создайте IServiceProvider, получите IHttpClientFactory, а затем получите настроенного клиента из IHttpClientFactory.

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

Многие люди считают, что использование IServiceProvider подобным образом является антишаблоном поиска служб в производственном коде;возможно, в тесте все нормально, чтобы вытащить конкретный элемент, который вы хотите протестировать, из конфигурации приложения по умолчанию.Тем не менее, существуют также более короткие способы теста для получения образца HttpClient, настроенного на HttpClientFactory, без использования полного WebApplicationFactory (см. Последнюю часть ответа).


Для полного завершениясквозной интеграционный тест, тестирование того, как ваше приложение использует настроенную политику, с использованием WebApplicationFactory для проверки конечной точки вашего приложения, например http://localhost:1234/api/v1/car/:

В рамках интеграционного теста вы могли бы использовать инструмент, подобный Mountebank для .NET или HttpClientInterception для блокирования вызовов, которые выполняет настроенный HttpClient, чтобы эти вызовы возвращали ошибки, которые, как вы ожидаете, будет обработана политикой.

Вы можете использовать возможность WebHostBuilder.ConfigureServices(...) для изменения обычного запуска вашего приложения, чтобы упростить утверждение чего-либо для подтверждения того, что политика была вызвана.Например, вы можете сконфигурировать ложную / фиктивную реализацию ILog и утверждать, что вызов ILog.Error(...) в вашем делегате onRetry имеет место.


Для самого короткого из возможных, автономныхмодульный тест для проверки политики Polly, настроенной для данной конфигурации HttpClient в HttpClientFactory, вы можете использовать шаблон кода, как показано ниже.При этом используются только 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() в опубликованном коде), подход, подобный приведенному выше, обеспечивает более ориентированный на юнит-тестированиеспособ проверить их.

...