C# 与 Docker 集成测试:高级进阶
\n集成测试是现代 .NET 应用程序中确保质量的关键环节。使用 Docker 可以创建隔离、可复现且尽可能接近生产环境的环境。在本文中,我们将探讨 C# 与 Docker 集成测试的高级技术:从配置 Testcontainers 到组织 CI/CD 流水线。
\n本文面向已熟悉单元测试基础和 Docker 基本概念的开发者。我们将深入探讨容器生命周期管理、多服务协作、调试以及测试执行时间的优化。
\n\n1. 为 .NET 配置 Testcontainers
\nTestcontainers 是一个库,它可以从测试代码中管理 Docker 容器。它会自动创建、启动和停止容器,确保每个测试的隔离性。
\n首先,在您的测试项目中安装该包:
\ndotnet add package Testcontainers\n一个基本示例——测试使用 PostgreSQL 的仓库:
\nusing Testcontainers.PostgreSql;\nusing Xunit;\n\npublic class UserRepositoryTests : IAsyncLifetime\n{\n private readonly PostgreSqlContainer _postgresContainer;\n\n public UserRepositoryTests()\n {\n // 配置 PostgreSQL 容器\n _postgresContainer = new PostgreSqlBuilder()\n .WithImage("postgres:15")\n .WithDatabase("testdb")\n .WithUsername("test")\n .WithPassword("test123")\n .WithCleanUp(true)\n .Build();\n }\n\n public async Task InitializeAsync()\n {\n // 在所有测试之前启动容器\n await _postgresContainer.StartAsync();\n }\n\n public async Task DisposeAsync()\n {\n // 停止并删除容器\n await _postgresContainer.DisposeAsync();\n }\n\n [Fact]\n public async Task AddUser_ShouldCreateUser()\n {\n // 获取容器的连接字符串\n var connectionString = _postgresContainer.GetConnectionString();\n var repository = new UserRepository(connectionString);\n\n await repository.AddUserAsync(new User { Name = "Test User" });\n var user = await repository.GetUserByNameAsync("Test User");\n\n Assert.NotNull(user);\n Assert.Equal("Test User", user.Name);\n }\n}\n重要提示:使用 IAsyncLifetime 来管理容器。这可以确保每个测试类都能获得一个全新的数据库实例。
2. 使用 Docker Compose 的多容器架构
\n实际应用程序依赖于多个服务:数据库、消息队列、缓存等。Testcontainers 支持 Docker Compose,从而可以启动整个基础设施。
\n安装额外的包:
\ndotnet add package Testcontainers.Compose\ndocker-compose.test.yml 文件示例:
version: '3.8'\nservices:\n postgres:\n image: postgres:15\n environment:\n POSTGRES_USER: test\n POSTGRES_PASSWORD: test\n POSTGRES_DB: testdb\n redis:\n image: redis:7-alpine\n在测试中使用:
\nusing Testcontainers.Compose;\n\npublic class OrderServiceTests\n{\n private readonly DockerComposeContainer _compose;\n\n public OrderServiceTests()\n {\n _compose = new DockerComposeContainer()\n .WithComposeFilePath("docker-compose.test.yml")\n .WithEnvironment("ASPNETCORE_ENVIRONMENT", "Testing")\n .Build();\n }\n\n [Fact]\n public async Task CreateOrder_ShouldSaveToDbAndCache()\n {\n await _compose.StartAsync();\n \n var dbConnection = _compose.GetConnectionString("postgres", 5432);\n var redisConnection = _compose.GetConnectionString("redis", 6379