Чтобы минимально изменить опубликованный код для получения именованного или напечатанного 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()
в опубликованном коде), подход, подобный приведенному выше, обеспечивает более ориентированный на юнит-тестированиеспособ проверить их.