如何配置JUnit测试套件以5线程运行,每个线程使用独立数据源?
基于JUnit 5 + Testcontainers实现多MySQL容器并行测试配置
1. 依赖准备
确保项目依赖中包含以下核心组件(以Maven为例):
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>mysql</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> </dependencies>
2. 开启JUnit 5并行执行
在src/test/resources/junit-platform.properties中配置并行规则,指定线程数为5:
junit.jupiter.execution.parallel.enabled = true junit.jupiter.execution.parallel.mode.default = concurrent junit.jupiter.execution.parallel.config.strategy = fixed junit.jupiter.execution.parallel.config.fixed.parallelism = 5
3. 实现线程隔离的MySQL容器管理
3.1 线程本地容器存储
用ThreadLocal保证每个测试线程持有独立的容器实例:
public class ThreadLocalMysqlContainer { private static final ThreadLocal<MySQLContainer<?>> CONTAINER = new ThreadLocal<>(); public static MySQLContainer<?> getContainer() { MySQLContainer<?> container = CONTAINER.get(); if (container == null) { container = new MySQLContainer<>("mysql:8.0") .withDatabaseName("test_db") .withUsername("test_user") .withPassword("test_pass"); container.start(); CONTAINER.set(container); } return container; } public static void closeContainer() { MySQLContainer<?> container = CONTAINER.get(); if (container != null) { container.stop(); CONTAINER.remove(); } } }
3.2 自定义JUnit扩展
扩展JUnit生命周期,为线程初始化/销毁容器,并动态覆盖Spring数据源配置:
public class MysqlContainerExtension implements BeforeAllCallback, AfterAllCallback, ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void beforeAll(ExtensionContext context) { ThreadLocalMysqlContainer.getContainer(); } @Override public void afterAll(ExtensionContext context) { ThreadLocalMysqlContainer.closeContainer(); } @Override public void initialize(ConfigurableApplicationContext applicationContext) { MySQLContainer<?> container = ThreadLocalMysqlContainer.getContainer(); TestPropertyValues.of( "spring.datasource.url=" + container.getJdbcUrl(), "spring.datasource.username=" + container.getUsername(), "spring.datasource.password=" + container.getPassword() ).applyTo(applicationContext.getEnvironment()); } }
4. 测试类集成配置
所有需要数据库的集成测试类继承基础测试类,禁用上下文缓存避免冲突:
@SpringBootTest @ExtendWith(MysqlContainerExtension.class) @TestInstance(TestInstance.Lifecycle.PER_CLASS) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) public class BaseIntegrationTest { // 其他测试类直接继承此类即可 }
关键注意事项
- 确保宿主机有足够CPU、内存资源运行5个MySQL容器
- Gradle用户需在
build.gradle中开启测试并行:test { useJUnitPlatform() { parallelExecution.set(true) } } - 测试中避免使用静态变量存储数据库状态,防止线程污染
内容的提问来源于stack exchange,提问作者Bruno Carneiro
相关产品推荐
相关产品推荐

