[英]Test Polly retry polly configured via Startup.ConfigureServices() with ASP.NET Core API
我想找出如何测试通过Startup.ConfigureServices()配置的Polly重试polly。
ConfigureServices
在其中配置了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
要最少修改您发布的代码以获取在HttpClient
配置的命名或键入的HttpClient
,请构建IServiceProvider
,获取IHttpClientFactory
,然后从IHttpClientFactory
获取配置的客户端。
var configuredClient = sc.BuildServiceProvider()
.GetRequiredService<IHttpClientFactory>()
.CreateClient("test");
许多人认为像这样使用IServiceProvider
是生产代码中的服务定位器反模式; 也许在测试中可以将要进行单元测试的特定项目从默认应用程序配置中拉出来。 但是,也有较短的测试方法来获取在HttpClient
配置的示例HttpClient,而不使用完整的WebApplicationFactory
(请参见答案的最后一部分)。
对于完整的端到端集成测试,请使用WebApplicationFactory
来测试应用程序如何使用配置的策略,以使用应用程序的某些终结点,例如http://localhost:1234/api/v1/car/
:
在集成测试中,您可以使用Mountebank for .NET或HttpClientInterception之类的工具来存根已配置的HttpClient
进行的调用,以使这些调用返回您希望策略处理的错误。
您可以使用WebHostBuilder.ConfigureServices(...)
来修改应用程序的正常启动,以使其易于断言以证明该策略已被调用。 例如,您可以配置模拟/伪造ILog
实现,并断言onRetry
委托中的ILog.Error(...)
调用已发生。
对于最短的,独立的单元测试,以测试在HttpClientFactory上给定HttpClient
配置上配置的Polly策略,您可以使用下面的代码模式。 这仅使用IHttpClientFactory和标准的Microsoft DI基础结构。 没有来自ASP.NET的Web主机。
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()
),则上述方法将提供一种以单元测试为重点的测试方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.