22

我有一个键入的客户端,我想将其注册为单例:

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因为这会带来我们之前在一个 long living 中遇到的所有问题HttpClient。显而易见的解决方案是注入一个HttpClientFactorynow 可用于在HttpClient每次键入客户端需要一个实例时发出一个实例,而不必担心生命周期管理等,因为这已推迟到HttpClientFactory现在。

我现在的问题是如何HttpClientFactory为一个简单的功能集成测试创建一个默认值,我想在其中实例化一个类型化的客户端,看看我是否可以点击 API 并从自动化测试中获得成功的响应?

我不想围绕它设置一个 ASP.NET Core TestServer 和一个完整的应用程序,因为这对于我现在想做的那种功能测试来说太过分了。

没有可用于注入的公共构造函数HttpClientFactory

4

3 回答 3

17

@dustinmoris 的回答,但在 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;
}
于 2020-07-29T13:57:30.567 回答
9

我现在的问题是如何为一个简单的功能集成测试创建一个默认的 HttpClientFactory,我想在其中实例化一个类型化的客户端,看看我是否可以点击 API 并从自动化测试中获得成功的响应?

您的测试可以采用您用于配置 HttpClientFactory 的确切代码StartUp(这是使用 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);
于 2019-01-24T21:11:17.667 回答
5

我只是自己创建一个用于测试(我认为可能已经有一种方法可以为我做到这一点):

type DefaultHttpClientFactory() =
    interface IHttpClientFactory with
        member __.CreateClient (name) =
            new HttpClient()
于 2018-09-30T09:16:48.387 回答