Java与Docker集成测试:从入门到精通
集成测试是开发的关键阶段,用于验证应用程序组件与外部系统(数据库、消息队列、REST服务)的交互。使用H2或内置服务器的传统方法常常导致测试环境与生产环境之间存在差异。解决方案是——Docker。本文将讲解如何使用Testcontainers库和Docker Compose配置Java应用与Docker的集成测试。您将学习如何编写与真实容器配合工作的测试,以及如何将其集成到CI/CD中。
为什么选择Docker进行集成测试?
Docker允许在测试前启动具有精确依赖版本(PostgreSQL、Redis、Kafka)的隔离容器,并在测试后销毁它们。这保证了:
- 与生产环境一致——使用真实数据库进行测试,而非模拟。
- 隔离性——每次测试运行都从干净状态开始。
- 并行运行——多个测试类可以使用不同的容器。
- 可重现性——测试在本地机器和CI中运行结果一致。
使用Testcontainers配置项目
Testcontainers 是一个管理Docker容器生命周期的Java库。在 pom.xml (Maven) 中添加依赖:
<dependency> <groupId>org.testcontainers</groupId> <artifactId>testcontainers</artifactId> <version>1.19.3</version> <scope>test</scope></dependency><dependency> <groupId>org.testcontainers</groupId> <artifactId>postgresql</artifactId> <version>1.19.3</version> <scope>test</scope></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope></dependency>对于Gradle,在 build.gradle 中添加:
testImplementation 'org.testcontainers:testcontainers:1.19.3'testImplementation 'org.testcontainers:postgresql:1.19.3'示例:测试PostgreSQL的Repository
考虑一个简单的用户管理服务。创建一个测试,启动PostgreSQL容器并验证数据保存。
import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.DynamicPropertyRegistry;import org.springframework.test.context.DynamicPropertySource;import org.testcontainers.containers.PostgreSQLContainer;import org.testcontainers.junit.jupiter.Container;import org.testcontainers.junit.jupiter.Testcontainers;
import static org.assertj.core.api.Assertions.assertThat;
@Testcontainers@SpringBootTestclass UserRepositoryTest {
@Container static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15") .withDatabaseName("testdb") .withUsername("test") .withPassword("test");
@DynamicPropertySource static void configureProperties(DynamicPropertyRegistry registry) { registry.add("spring.datasource.url", postgres::getJdbcUrl); registry.add("spring.datasource.username", postgres::getUsername); registry.add("spring.datasource.password", postgres::getPassword); }
@Autowired private UserRepository userRepository;
@Test void shouldSaveAndFindUser() { User user = new User("john_doe", "john@example