C# 与 Docker 集成测试:从 A 到 Z
集成测试是任何严肃 C# 应用程序开发中至关重要的阶段。它检查系统的各个组件(数据库、外部 API、文件系统)如何协同工作。然而,测试环境的配置常常令人头疼:需要启动真实的服务器、测试后清理数据,并应对环境的不稳定性。Docker 通过提供轻量、隔离且可重现的容器解决了这些问题。在本文中,我们将详细讲解如何从零开始配置 C# 与 Docker 的集成测试,直至构建一个可用的流水线。
为什么 Docker 是 C# 集成测试的理想选择?
传统方法是使用本地 SQL Server 数据库或外部服务的模拟器。这会导致以下问题:
- 数据污染:测试会在数据库中留下垃圾数据,影响其他测试。
- 环境不兼容:开发人员机器上的 DBMS 版本与 CI 服务器上的不同。
- 并行运行困难:测试会因端口和资源冲突。
Docker 可以轻松解决这些问题:每个测试(或测试组)都会获得自己独立的容器,其中包含所需版本的数据库、Redis 或其他服务。容器轻量、启动迅速,并在测试完成后保证被销毁。对于 .NET 开发者来说,这尤其重要,得益于 Testcontainers for .NET 库,它可以直接从测试代码中自动管理容器。
项目配置:将 Docker 添加到 C# 测试中
首先,我们创建一个包含集成测试的项目。假设我们有一个基于 .NET 8 的 Web API,它与 PostgreSQL 配合使用。我们需要测试创建用户的端点。
步骤 1:安装 NuGet 包
将以下包添加到测试项目中:
dotnet add package Testcontainers.PostgreSqldotnet add package Microsoft.AspNetCore.Mvc.Testingdotnet add package FluentAssertionsTestcontainers.PostgreSql 是 Docker SDK 的一个封装,用于管理 PostgreSQL 容器。Microsoft.AspNetCore.Mvc.Testing 允许在内存中运行 Web 应用程序以进行测试。
步骤 2:创建测试基类
创建一个抽象类,用于在测试前启动数据库容器:
using Testcontainers.PostgreSql;using Xunit;
public abstract class IntegrationTestBase : IAsyncLifetime{ private readonly PostgreSqlContainer _postgresContainer;
protected string ConnectionString => _postgresContainer.GetConnectionString();
protected IntegrationTestBase() { _postgresContainer = new PostgreSqlBuilder() .WithImage("postgres:16-alpine") .WithDatabase("testdb") .WithUsername("test") .WithPassword("test123") .Build(); }
public async Task InitializeAsync() { await _postgresContainer.StartAsync(); }
public async Task DisposeAsync() { await _postgresContainer.StopAsync(); }}该类实现了 xUnit 中的 IAsyncLifetime 接口,确保在所有测试之前启动容器,并在测试之后停止容器。ConnectionString 从容器动态获取——端口可以是任意空闲端口。
步骤 3:使用 Testcontainers 和 WebApplicationFactory 编写测试
现在编写测试本身。我们将使用 WebApplicationFactory 创建测试 HTTP 客户端:
using Microsoft.AspNetCore.Mvc.Testing;using FluentAssertions;using System.Net.Http.Json;
public class UserApiTests : IntegrationTestBase{ private readonly WebApplicationFactory<Program> _factory;
public UserApiTests()