在单个集成测试中,可以托管多个通信实例的WebApplicationFactory。
假设我们有名为WebApplication
的主服务,它使用名为“WebService”的命名HttpClient依赖于名为WebService
的实用程序服务。
以下是集成测试示例:
[Fact]
public async Task GetWeatherForecast_ShouldReturnSuccessResult()
这段代码需要实现CustomWebApplicationFactory
类:
internal sealed class CustomWebApplicationFactory
: WebApplicationFactory<WebApplication.Startup>
{
private ConcurrentDictionary<string, HttpClient> HttpClients { get; } =
new ConcurrentDictionary<string, HttpClient>();
public void AddHttpClient(string clientName, HttpClient client)
{
if (!HttpClients.TryAdd(clientName, client))
{
throw new InvalidOperationException(
$"HttpClient with name {clientName} is already added");
}
}
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
base.ConfigureWebHost(builder);
builder.ConfigureServices(services =>
services.AddSingleton<IHttpClientFactory>(
new CustomHttpClientFactory(HttpClients)));
}
}
最后,需要
CustomHttpClientFactory
类:
internal class CustomHttpClientFactory : IHttpClientFactory
private IReadOnlyDictionary<string, HttpClient> HttpClients
public HttpClient CreateClient(string name) =>
HttpClients.GetValueOrDefault(name)
?? throw new InvalidOperationException(
$"HTTP client is not found for client with name ");
}
你可以在这里找到完整的示例代码:https://github.com/GennadyGS/AspNetCoreIntegrationTesting
这种方法的优点是:
- 能够测试服务之间的交互;
- 无需模拟服务内部,因此可以将其视为黑盒;
- 测试对任何重构都稳定,包括通信协议更改;
- 测试速度快,自包含,不需要任何先决条件,并提供可预测的结果。
这种方法的主要缺点是可能会存在参与服务的冲突依赖项(例如,EFCore 的不同主要版本)在现实世界的场景中,因为所有用于测试的服务都在单个进程中运行。
有几种缓解这个问题的方法。其中之一是对服务实现应用模块化方法,并根据配置文件在运行时加载模块。这可以允许在测试中替换配置文件、排除几个模块的加载并用简单的模拟替换丢失的服务。您可以在上面示例存储库的 "Modular" 分支中找到应用此方法的示例。