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

Spring Boot采用单例Testcontainers方案时为何启动2个测试容器?

问题原因

你当前的配置之所以会启动两个容器,是因为Testcontainers的复用特性未全局开启,且不同测试上下文加载时静态块可能被重复触发,同时Maven测试插件如果开启了多进程fork也会导致容器重复创建。

解决步骤

1. 重写容器基类,用枚举实现严格单例

枚举是JVM层面保证的单例实现,能确保整个测试生命周期中只有一个容器实例:

import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.lifecycle.Startables;

public  class PostgresTestContainer {
    // 枚举单例保证全局唯一
    enum SingletonPostgresContainer {
        INSTANCE;

        private final PostgreSQLContainer<?> container;

        SingletonPostgresContainer() {
            container = new PostgreSQLContainer<>("postgres:12")
                    .withDatabaseName("test")
                    .withUsername("postgres")
                    .withPassword("postgres")
                    .withReuse(true);
        }

        public PostgreSQLContainer<?> getContainer() {
            return container;
        }
    }

    static final PostgreSQLContainer<?> postgreSQLContainer = SingletonPostgresContainer.INSTANCE.getContainer();

    static {
        // 异步启动保证容器就绪
        Startables.deepStart(postgreSQLContainer).join();
    }

    @DynamicPropertySource
    static void datasourceConfig(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgreSQLContainer::getJdbcUrl);
        registry.add("spring.datasource.password", postgreSQLContainer::getPassword);
        registry.add("spring.datasource.username", postgreSQLContainer::getUsername);
    }
}

2. 开启Testcontainers全局复用配置

在src/test/resources目录下新增testcontainers.properties文件,添加如下配置:

testcontainers.reuse.enable=true

3. 配置Maven测试插件使用单进程

如果测试插件开启了多进程fork,每个进程都会初始化独立的容器,修改pom.xml中Surefire和Failsafe插件配置:

<build>
    <plugins>
        <!-- 单元测试插件 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.22.2</version>
            <configuration>
                <forkCount>1</forkCount>
                <reuseForks>true</reuseForks>
            </configuration>
        </plugin>
        <!-- 集成测试插件 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>2.22.2</version>
            <configuration>
                <forkCount>1</forkCount>
                <reuseForks>true</reuseForks>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>integration-test</goal>
                        <goal>verify</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

可选优化

你当前的Repository测试类使用的是JUnit 4的@RunWith(SpringRunner.class),而你用的是JUnit 5,Spring Boot 2.5+的@DataJpaTest已经默认集成了Spring拓展,直接删除该注解即可,避免版本冲突。

内容的提问来源于stack exchange,提问作者wick3d

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 15:36:05