从 WebApplicationFactory 注入 HttpClient

Inject HttpClient from WebApplicationFactory

我正在尝试创建(大部分)统一的集成测试集,这些测试可以针对从 WebApplicationFactory 创建的内存中 API 或完全部署的版本我们的应用程序。使用 XUnit.DependencyInjection,我计划在我的测试中注入一个 HttpClient,它指向测试服务器或基于环境变量的真实应用程序。

所以要为测试服务器创建一个客户端,我可以 运行 Startup.cs 中的以下内容:

WebApplicationFactory<Program> app = new();
HttpClient client = app.CreateClient();

这似乎有效。但是,我完全不知道如何将 HttpClient 的这个实现注入到单独的测试 classes.

像这样的东西不起作用(这样的重载不存在):

services.AddHttpClient<MyTestClass>(client);

这也不行(注入的客户端出于某种原因将 BaseAddress 设置为 null):

services.AddHttpClient<InMemoryServerSelfTests>(c =>
                                    {
                                        c.BaseAddress           = client.BaseAddress;
                                        c.Timeout               = client.Timeout;
                                    });

我唯一的其他想法是创建一个新的 class 来包装两个客户端并注入它,但这看起来很乱:

public class TestClientWrapper
{
    public readonly HttpClient Client;
    public TestClientWrapper(InMemoryTestServer server)
    {
        Client = server.CreateClient();
    }

    public TestClientWrapper(HttpClient client)
    {
        Client = client;
    }
}

// In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    string targetEndpoint = Environment.GetEnvironmentVariable("targetEndpoint"); // Make this configurable
    bool   isLocal        = string.IsNullOrEmpty(targetEndpoint);
    
    if (isLocal)
    {
        InMemoryTestServer app = new();
        services.AddSingleton(new TestClientWrapper(app));
    }
    else
    {
        HttpClient client = new();
        services.AddSingleton(new TestClientWrapper(client));
    }
}

真的,我有点难过...关于如何完成这个的任何想法?

问题是 WebApplicationFactory 生成的 HttpClient 是特殊的,因为 WebApplicationFactory 托管在内存中并且在进程外不可见(我想这就是我读到的别处)。这意味着复制设置不起作用。

我设法让 WebApplicationFactory 客户端注册以使其可解析的唯一方法是向 returns 客户端的容器注册 IHttpClientFactory 的实例WebApplicationFactory.

class TestClientFactory : IHttpClientFactory
{
    WebApplicationFactory<Startup> _appFactory;

    public TestClientFactory(TestClientFactory _appFactory) => this._appFactory= appFactory;

    public HttpClient CreateClient(string name) => this._appFactory.CreateClient();
}

services.AddSingleton<IHttpClientFactory>(new TestClientFactory(...));

按照这些思路行事。