You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 13:39:00