我有一个类型化的客户端,我想注册为单身人士:
public class SomeHttpClient
{
private readonly IHttpClientFactory _clientFactory;
public SomeHttpClient(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public Task MakeSomeCallAsync(...)
{
var client = _clientFactory.Create();
// Do more stuff
}
}
类型化的客户端必须为单例,因为它具有一些断路器逻辑,如果API对客户端进行速率限制,则该逻辑会断开电路。必须在整个应用程序中断开电路,并且显然不仅要断开当前的请求管道(否则客户端将继续使用已经受其他实例限制的API)。这已经通过使用封装该功能的类型化客户端(尽管不是Polly)来实现。
现在,由于类型化的客户端将是一个单例,因此我们无法注入单个HttpClient
,因为这将带来我们一个单一的长寿HttpClient
所遇到的所有问题。显而易见的解决方案是注入一个HttpClientFactory
,该类型现在可以用于在每次键入的客户端需要一个实例时发出一个HttpClient
实例,而不必担心生命周期管理等问题,因为该实例已推迟到{ {1}}。
我现在的问题是如何为简单的功能集成测试创建默认的HttpClientFactory
,在该实例中我想实例化类型化的客户端,看看是否可以使用API并从自动化测试中获得成功的响应?
我不想设置一个ASP.NET Core TestServer及其周围的整个应用程序,因为这对于我现在想要进行的功能测试来说是一个过大的选择。
没有可用于注入HttpClientFactory
的公共构造函数吗?
答案 0 :(得分:9)
@dustinmoris' answer,但使用C#
public sealed class DefaultHttpClientFactory : IHttpClientFactory
{
public HttpClient CreateClient(string name) => new HttpClient();
}
甚至更好,请使用单个:
public sealed class DefaultHttpClientFactory : IHttpClientFactory
{
private static readonly Lazy<HttpClient> _httpClientLazy =
new Lazy<HttpClient>(() => new HttpClient());
// NOTE: This will always return the same HttpClient instance.
public HttpClient CreateClient(string name) => _httpClientLazy.Value;
}
答案 1 :(得分:0)
我只是创建一个自己进行测试(我想也许已经有一种方法可以为我做这件事):
type DefaultHttpClientFactory() =
interface IHttpClientFactory with
member __.CreateClient (name) =
new HttpClient()
答案 2 :(得分:0)
我现在的问题是如何为简单的功能集成测试创建默认的HttpClientFactory,以在该实例中实例化类型化的客户端,看看是否可以使用API并从自动化测试中获得成功的响应?
您的测试可以获取您在StartUp
中配置HttpClientFactory所使用的确切代码(这是使用Polly策略的示例,但可以是HttpClientFactory上的任何配置)。
IServiceCollection services = new ServiceCollection(); // [1]
services.AddHttpClient(TestClient)
.AddPolicyHandler(HttpPolicyExtensions.HandleTransientHttpError()
.RetryAsync(3); // [2]
第[2]行可能是您的StartUp
类中的确切代码。您可以将其从普通的ConfigureServices(...)
方法中分解为一个单独的static
方法,您的测试也可以调用该方法-这样您的测试就可以正确测试StartUp
的配置。
然后在测试中:
IHttpClientFactory factory = services
.BuildServiceProvider()
.GetRequiredService<IHttpClientFactory>();
var sut = new SomeHttpClient(factory);