C# 为集成测试创建默认HttpClientFactory

C# 为集成测试创建默认HttpClientFactory,c#,asp.net-core,.net-core,dotnet-httpclient,httpclientfactory,C#,Asp.net Core,.net Core,Dotnet Httpclient,Httpclientfactory,我有一个类型化客户端,我想注册为singleton: public class SomeHttpClient { private readonly IHttpClientFactory _clientFactory; public SomeHttpClient(IHttpClientFactory clientFactory) { _clientFactory = clientFactory; } public Task MakeSom

我有一个类型化客户端,我想注册为singleton:

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,而API已经受到其他实例的速率限制)。这已经通过使用封装该功能的类型化客户端实现了(但不是Polly)

现在,由于类型化客户端将是一个单例客户端,我们不能注入单个
HttpClient
,因为这将带来我们以前在单个长寿
HttpClient
上遇到的所有问题。显而易见的解决方案是注入一个
HttpClientFactory
,现在每当类型化的客户端需要一个
HttpClient
实例时,就可以使用该实例来发出一个
HttpClientFactory
实例,而不必担心生命周期管理等问题,因为这已经推迟到
HttpClientFactory

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

我不想设置一个ASP.NET核心测试服务器和围绕它的整个应用程序,因为这对于我现在想做的那种功能测试来说是一种过分的做法


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

我只是自己创建了一个用于测试的构造函数(我想可能已经有一种方法可以为我做到这一点):

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

您的测试可以获取用于在
启动
中配置HttpClientFactory的确切代码(这是一个使用Polly策略的示例,但它可以是HttpClientFactory上的任何配置)

第[2]行可能是
启动
类中的确切代码。您可以将它从正常的
ConfigureServices(…)
方法中分离出来,转换为一个单独的
static
方法,您的测试也可以调用该方法-因此,您的测试可以准确地测试
StartUp
配置的内容

然后在测试中:

IHttpClientFactory factory = services
    .BuildServiceProvider()
    .GetRequiredService<IHttpClientFactory>();

var sut = new SomeHttpClient(factory);
IHttpClientFactory=服务
.BuildServiceProvider()
.GetRequiredService();
var sut=新的某个HttpClient(工厂);
,但使用C#

或者更好的方法是使用单例:

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;
}
公共密封类DefaultHttpClientFactory:IHttpClientFactory
{
私有静态只读惰性\u httpClientLazy=
新的惰性(()=>newhttpclient());
//注意:这将始终返回相同的HttpClient实例。
公共HttpClient CreateClient(字符串名称)=>\u httpClientLazy.Value;
}

拜托,F#是个骗子!与C#verbosity=)相比,这是一个很好的答案(如果您转换回C#),因为我实际上希望在集成测试中发送数据。使用此方法,您可以完全控制。很不错的!
IHttpClientFactory factory = services
    .BuildServiceProvider()
    .GetRequiredService<IHttpClientFactory>();

var sut = new SomeHttpClient(factory);
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;
}