【发布时间】:2020-07-22 10:20:36
【问题描述】:
我创建了一个自定义库,它可以为依赖于 HttpClient 的特定服务自动设置 Polly 策略。
这是使用IServiceCollection 扩展方法和类型化客户端方法完成的。一个简化的例子:
public static IHttpClientBuilder SetUpFooServiceHttpClient(this IServiceCollection services)
{
return services
.AddHttpClient<FooService>()
.AddPolicyHandler(GetRetryPolicy());
}
public class FooService
{
private readonly HttpClient _client;
public FooService(HttpClient httpClient)
{
_client = httpClient;
}
public void DoJob()
{
var test = _client.GetAsync("http://example.com");
}
}
请注意,我的真实代码使用泛型类型和选项生成器,但为了简单起见,我省略了该部分。我的测试的目的是确认我的选项生成器正确地应用了我希望它应用的策略。为了此处的示例,我们假设这是我要测试的硬编码重试策略。
我现在想测试这个库是否正确地将 Polly 策略注册到我注入的 HttpClient 依赖项中。
注意
网上和 StackOverflow 上有很多答案,建议您自己构建HttpClient,即:@ 987654326@,但这违背了我需要测试实际IHttpClientFactory是否正在使用请求的策略构造 httpclients 的目的。
为此,我想用 real HttpClient 进行测试,它由 real IHttpClientFactory 生成,但我希望它的处理程序被模拟我可以避免发出实际的网络请求并人为地导致错误的响应。
我正在使用AddHttpMessageHandler() 注入一个模拟处理程序,但工厂似乎忽略了这一点。
这是我的测试夹具:
public class BrokenDelegatingHandler : DelegatingHandler
{
public int SendAsyncCount = 0;
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
SendAsyncCount++;
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.InternalServerError));
}
}
private BrokenDelegatingHandler _brokenHandler = new BrokenDelegatingHandler();
private FooService GetService()
{
var services = new ServiceCollection();
services.AddTransient<BrokenDelegatingHandler>();
var httpClientBuilder = services.SetUpFooServiceHttpClient();
httpClientBuilder.AddHttpMessageHandler(() => _brokenHandler);
services.AddSingleton<FooService>();
return services
.BuildServiceProvider()
.GetRequiredService<FooService>();
}
这是我的测试:
[Fact]
public void Retries_client_connection()
{
int retryCount = 3;
var service = GetService();
_brokenHandler.SendAsyncCount.Should().Be(0); // PASS
var result = service.DoJob();
_brokenHandler.SendAsyncCount.Should().Be(retryCount); // FAIL: expected 3 but got 0
}
当我调试测试时,处理程序的断点永远不会被命中,并且响应返回为 200(因为它实际上连接到 URL,而不是命中模拟的处理程序)。
为什么 http 客户端工厂忽略了我的模拟处理程序?
请注意,我也将接受任何允许我以另一种有效方式测试策略的答案。
我知道我可以只使用损坏的 URL 字符串,但我需要在测试中测试特定的 http 响应。
【问题讨论】:
标签: c# unit-testing mocking polly httpclientfactory