Spring JUnit5通过ExtendWith复用TestContainer出现5432端口连接拒绝问题
问题解决方案
根本原因
- Spring 的
@DynamicPropertySource注解仅会扫描当前测试类中的静态方法,写在自定义 JUnit Extension 中的该注解方法不会被 Spring 识别执行,导致 Spring 仍然使用默认的localhost:5432数据库配置,触发连接拒绝报错。 - Testcontainers 的
@Container注解仅会处理标注了@Testcontainers注解的测试类内部的字段,Extension 内部的@Container注解不会被 Testcontainers 自动处理,属于冗余配置。 - 额外的隐藏问题:你定义了 MariaDB 镜像变量,但实例化的是
PostgreSQLContainer,容器镜像与类型不匹配,后续会导致容器启动失败。
修复步骤
1. 修改自定义 Extension 代码
移除无效注解,在容器启动成功后手动注入数据源配置,同时修正镜像与容器类型的匹配逻辑:
public class PostgresTestContainersExtension implements BeforeAllCallback, BeforeTestExecutionCallback { // 若确实使用MariaDB请替换为MariaDBContainer类,此处统一匹配PostgreSQL容器类型 private static final String IMAGE_NAME = "postgres:14-alpine"; public static PostgreSQLContainer container = new PostgreSQLContainer(IMAGE_NAME) .withUsername("duke") .withPassword("password") .withDatabaseName("test"); @Override public void beforeAll(ExtensionContext extensionContext) { startContainerIfNeed(); // 手动注入数据源配置,优先级高于配置文件中的默认值 System.setProperty("spring.datasource.url", container.getJdbcUrl()); System.setProperty("spring.datasource.username", container.getUsername()); System.setProperty("spring.datasource.password", container.getPassword()); } @Override public void beforeTestExecution(ExtensionContext extensionContext) { startContainerIfNeed(); } public void startContainerIfNeed() { if (!container.isRunning()) { container.start(); } } }
2. 清理测试类冗余注解
测试类上的 @Testcontainers 注解用于处理测试类内部的 @Container 字段,当前场景下可以直接移除:
@SpringBootTest @ExtendWith({PostgresTestContainersExtension.class}) public class ApplicationJUnit5Test { @Autowired private HeroClassicJDBCRepository repositoryUnderTest; @Test public void test1() { System.out.println("junit version: " + Version.id()); Collection<Hero> heroes = repositoryUnderTest.allHeros(); assertThat(heroes).hasSize(1); repositoryUnderTest.addHero(new Hero("bb", "bb")); Collection<Hero> heroesAfter = repositoryUnderTest.allHeros(); assertThat(heroesAfter).hasSize(2); } }
可选优化
如果不想用系统属性注入配置,可以让自定义Extension同时实现 ApplicationContextInitializer<ConfigurableApplicationContext>,在上下文初始化阶段通过 DynamicPropertyRegistry 注入配置,兼容性更强。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

