使用Docker进行C#集成测试:高级水平
集成测试是C#开发中至关重要的阶段,它允许检查系统组件与真实依赖项(如数据库、消息队列、外部API)的交互。使用Docker进行此目的已成为行业标准,但在高级水平上,会出现隔离、性能和并行执行的问题。在本文中,我们将使用Testcontainers库和高级配置,剖析使用Docker进行C#集成测试的专业技术。
1. 为.NET配置Testcontainers:基础基础设施
用于.NET的Testcontainers库允许在测试环境中以编程方式管理Docker容器。与手动运行docker-compose不同,Testcontainers会自动为每个测试类或模块启动和停止容器,确保环境清洁。
通过NuGet安装包:
dotnet add package Testcontainers --version 3.9.0dotnet add package Testcontainers.PostgreSql --version 3.9.0dotnet add package Testcontainers.MsSql --version 3.9.0使用PostgreSQL的集成测试基类示例:
using Testcontainers.PostgreSql;using Xunit;
public class DatabaseFixture : IAsyncLifetime{ private readonly PostgreSqlContainer _container = new PostgreSqlBuilder() .WithImage("postgres:15-alpine") .WithDatabase("testdb") .WithUsername("testuser") .WithPassword("testpass") .Build();
public string ConnectionString => _container.GetConnectionString();
public async Task InitializeAsync() { await _container.StartAsync(); }
public async Task DisposeAsync() { await _container.StopAsync(); }}现在,每个测试类都可以使用此fixture来获取隔离的数据库实例。
2. 测试隔离和容器状态管理
高级水平需要对隔离进行精细控制。不要为整个测试套件使用一个容器,而是为每个测试类甚至每个测试使用一个容器。这可以防止测试之间数据库的“脏”状态。
通过xUnit中的Collection属性实现:
[CollectionDefinition("Database collection")]public class DatabaseCollection : ICollectionFixture<DatabaseFixture>{}
[Collection("Database collection")]public class UserRepositoryTests{ private readonly DatabaseFixture _fixture;
public UserRepositoryTests(DatabaseFixture fixture) { _fixture = fixture; }
[Fact] public async Task CreateUser_ShouldPersistUser() { // Arrange await using var context = new AppDbContext(_fixture.ConnectionString); await context.Database.EnsureCreatedAsync(); var repo = new UserRepository(context);
// Act var user = new User { Name = "Test User" }; await repo.CreateAsync(user);
// Assert var savedUser = await context.Users.FindAsync(user.Id); Assert.NotNull(savedUser); }}为了在测试级别实现完全隔离,使用ITestOutputHelper并在DisposeAsync方法内创建容器:
public class IsolatedTest : IAsyncLifetime{ private PostgreSqlContainer _container;
public async Task InitializeAsync() { _container = new PostgreSqlBuilder().Build(); await _container.StartAsync(); }
public async Task DisposeAsync() { await _container.DisposeAsync(); }}3. 并行运行测试和资源管理
主要挑战之一