创建默认的HttpClientFactory进行集成测试

时间:2018-09-30 09:03:56

标签: c# asp.net-core .net-core dotnet-httpclient httpclientfactory

我有一个类型化的客户端,我想注册为单身人士:

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的公共构造函数吗?

3 个答案:

答案 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);