如何通过自定义注解配置TestContainer测试,无需使用抽象类
如何通过自定义注解配置TestContainer测试,无需使用抽象类
我完全理解你不想用抽象类的诉求——继承层级会给测试类带来不必要的约束,用自定义注解来统一配置才是更优雅的解决方案。针对你使用的Spring Boot 2.7.18版本(没有@ServiceContainer注解),我们可以通过自定义Spring测试监听器结合注解元数据来实现你的需求,下面是具体步骤:
第一步:编写TestContainer的测试执行监听器
创建一个Spring TestExecutionListener,负责启动/停止MariaDB容器,并自动注册数据源属性到Spring环境中:
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.MutablePropertySources; import org.springframework.test.context.TestContext; import org.springframework.test.context.support.AbstractTestExecutionListener; import org.testcontainers.containers.MySQLContainer; import org.testcontainers.utility.DockerImageName; import java.util.Map; public class MariaDbTestContainerExecutionListener extends AbstractTestExecutionListener { // 静态容器实例,确保所有测试类共享同一个容器,避免重复启动 private static final MySQLContainer<?> MYSQL_CONTAINER = new MySQLContainer<>( DockerImageName.parse("library/mariadb") .asCompatibleSubstituteFor("mysql") ); @Override public void beforeTestClass(TestContext testContext) throws Exception { super.beforeTestClass(testContext); // 启动容器 MYSQL_CONTAINER.start(); // 获取Spring上下文,注册动态数据源属性 ConfigurableApplicationContext applicationContext = testContext.getApplicationContext(); ConfigurableEnvironment environment = applicationContext.getEnvironment(); MutablePropertySources propertySources = environment.getPropertySources(); propertySources.addFirst(new MapPropertySource("testContainerProperties", Map.of( "spring.datasource.url", MYSQL_CONTAINER.getJdbcUrl(), "spring.datasource.username", MYSQL_CONTAINER.getUsername(), "spring.datasource.password", MYSQL_CONTAINER.getPassword() ))); } @Override public void afterTestClass(TestContext testContext) throws Exception { super.afterTestClass(testContext); // 测试类执行完成后停止容器 MYSQL_CONTAINER.stop(); } }
第二步:完善自定义测试注解@MyTestConfig
在你的自定义注解中,除了原来的Spring测试注解,还要添加@TestExecutionListeners来引入上面的监听器,同时设置合并模式保留默认的监听器:
import org.springframework.test.context.TestExecutionListeners; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.testcontainers.junit.jupiter.Testcontainers; import java.lang.annotation.*; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Inherited @DataJpaTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @Testcontainers @TestExecutionListeners( listeners = MariaDbTestContainerExecutionListener.class, mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS ) public @interface MyTestConfig { }
第三步:编写简化的测试类
现在你的测试类只需要标注@MyTestConfig即可,完全不需要再写容器定义和属性配置代码,和你最开始想要的简洁形式一致:
@MyTestConfig class MyTests { @Autowired SomeJpaRepo repo; @Test void findAll() { assertThatCode(repo::findAll).doesNotThrowAnyExceptions(); } }
额外说明
- 静态的容器实例会让所有使用
@MyTestConfig的测试类共享同一个MariaDB容器,大大减少测试启动时间; - 测试监听器会自动在测试类执行前启动容器、注册属性,执行完成后停止容器,完全不需要手动管理;
- 这种方式完全避免了抽象类的继承约束,测试类的结构更清爽。
备注:内容来源于stack exchange,提问作者Archimedes Trajano
相关产品推荐
相关产品推荐

