使用 dotnet-testcontainers 进行 ASP.NET Core 集成测试

roc*_*sen 9 c# integration-testing asp.net-core

我正在尝试按照文档为 aspnetcore v6 webapi 添加一些集成测试 - https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-6.0#aspnet-core -集成测试

我的 webapi 数据库是 SQLServer。我希望针对实际的 SQLServer 数据库而不是内存数据库运行测试。我遇到了 dotnet-testcontainers - https://github.com/HofmeisterAn/dotnet-testcontainers并考虑使用它,这样我就不需要担心重置数据库,因为一旦运行测试,容器就会被删除。

这就是我打算做的:

  1. 在启动测试 Web 主机之前启动 SQLServer 测试容器。在本例中,测试 Web 主机是使用 WebApplicationFactory 启动的。所以启动的wen主机有一个数据库可以连接。否则服务启动会失败。
  2. 运行测试。该测试将在运行之前添加一些测试数据。
  3. 然后删除 SQLServer 测试容器以及测试 Web 主机的处置。

这样我就可以启动连接到容器中运行的干净数据库的测试 Web 主机,运行测试。

这种方法听起来正确吗?或者是否有人使用 dotnet-testcontainers 来启动容器以进行应用程序测试以及哪种方法有效。

Mat*_*tze 11

在这里写了关于这种方法的文章。

您基本上需要创建一个自定义WebApplicationFactory连接字符串,并将数据库上下文中的连接字符串替换为指向测试容器的连接字符串。

这是一个示例,只需要稍微调整即可匹配 MSSQL docker 映像。

public class IntegrationTestFactory<TProgram, TDbContext> : WebApplicationFactory<TProgram>, IAsyncLifetime
    where TProgram : class where TDbContext : DbContext
{
    private readonly TestcontainerDatabase _container;

    public IntegrationTestFactory()
    {
        _container = new TestcontainersBuilder<PostgreSqlTestcontainer>()
            .WithDatabase(new PostgreSqlTestcontainerConfiguration
            {
                Database = "test_db",
                Username = "postgres",
                Password = "postgres",
            })
            .WithImage("postgres:11")
            .WithCleanUp(true)
            .Build();
    }

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureTestServices(services =>
        {
            services.RemoveProdAppDbContext<TDbContext>();
            services.AddDbContext<TDbContext>(options => { options.UseNpgsql(_container.ConnectionString); });
            services.EnsureDbCreated<TDbContext>();
        });
    }

    public async Task InitializeAsync() => await _container.StartAsync();

    public new async Task DisposeAsync() => await _container.DisposeAsync();
}
Run Code Online (Sandbox Code Playgroud)

以下是替换和初始化数据库上下文的扩展方法。

public static class ServiceCollectionExtensions
{
    public static void RemoveDbContext<T>(this IServiceCollection services) where T : DbContext
    {
        var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<T>));
        if (descriptor != null) services.Remove(descriptor);
    }

    public static void EnsureDbCreated<T>(this IServiceCollection services) where T : DbContext
    {
        var serviceProvider = services.BuildServiceProvider();

        using var scope = serviceProvider.CreateScope();
        var scopedServices = scope.ServiceProvider;
        var context = scopedServices.GetRequiredService<T>();
        context.Database.EnsureCreated();
    }
}
Run Code Online (Sandbox Code Playgroud)