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

MongoDB Atlas Local容器集成测试连接失败问题求助

问题:MongoDB Atlas Local测试容器连接失败,集成测试无法运行

我正在为一个响应式服务编写集成测试,但在连接MongoDB Atlas Local测试容器时始终失败,两种场景下分别抛出不同异常:

  1. 添加@ServiceConnection注解时:

Caused by: org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsNotFoundException: No ConnectionDetails found for source '@ServiceConnection source for MovieServiceIT.mongoDBContainer'

  1. 移除@ServiceConnection注解时:

org.springframework.dao.DataAccessResourceFailureException: Timed out while waiting for a server that matches WritableServerSelector. Client view of cluster state is {type=UNKNOWN, servers=[{address=localhost:27017, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketOpenException: Exception opening socket}, caused by {io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: localhost/[0:0:0:0:0:0:0:1]:27017}, caused by {java.net.ConnectException: Connection refused}}]


测试类代码(MovieServiceIT)

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Testcontainers
@ExtendWith(SpringExtension.class)
@AutoConfigureWebTestClient
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@DisplayName("Testing Movies API")
class MovieServiceIT {

    @Container
    @ServiceConnection
    static MongoDBAtlasLocalContainer mongoDBContainer = new MongoDBAtlasLocalContainer("mongodb/mongodb-atlas-local:8.0.3");

    @Autowired
    private WebTestClient webTestClient;

    @Autowired
    private MoviesRepository moviesRepository;


    @BeforeEach
    void setUp() throws IOException {
        assertThat(mongoDBContainer.isCreated()).isTrue();
        assertThat(mongoDBContainer.isRunning()).isTrue();

        movies = DataLoadUtil.loadTestModels("resources/data/movies.json"); // This works

        moviesRepository.deleteAll()
                .thenMany(
                        Flux.just(movies.toArray(new Movie[]{})).flatMap(moviesRepository::save)
                )
                .blockLast();
    }

    @Test
    @Order(1)
    @DisplayName("Endpoint: GET /movies/{id}")
    void getMovieById() throws Exception {
        webTestClient.get()
                .uri("/movies/573a1392f29313caabcdae3d")
                .exchange()
                .expectStatus().isOk()
                .expectBody(Movie.class)
                .consumeWith(response -> {
                    assertEquals("Modern Times", Objects.requireNonNull(response.getResponseBody()).getTitle());
                });
    }
}

pom.xml主要依赖配置

<dependencies>
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-otlp</artifactId>
        <scope>runtime</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    </dependency>

    <!-- TESTING //-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-testcontainers</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>io.projectreactor</groupId>
        <artifactId>reactor-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.testcontainers</groupId>
        <artifactId>junit-jupiter</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.testcontainers</groupId>
        <artifactId>mongodb</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-docker-compose</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <dependency>
        <groupId>org.springframework.restdocs</groupId>
        <artifactId>spring-restdocs-webtestclient</artifactId>
        <scope>test</scope>
    </dependency>

    <!-- BUILD //-->
    <dependency>
        <groupId>org.springdoc</groupId>
        <artifactId>springdoc-openapi-starter-common</artifactId>
        <version>2.7.0</version>
    </dependency>
    <dependency>
        <groupId>org.springdoc</groupId>
        <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
        <version>2.8.0</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.restdocs</groupId>
        <artifactId>spring-restdocs-mockmvc</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>io.swagger.core.v3</groupId>
        <artifactId>swagger-models</artifactId>
        <version>2.2.9</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-failsafe-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>integration-test</goal>
                        <goal>verify</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <excludes>
                    <exclude>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                    </exclude>
                </excludes>
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.graalvm.buildtools</groupId>
            <artifactId>native-maven-plugin</artifactId>
        </plugin>
        <plugin>
            <groupId>org.asciidoctor</groupId>
            <artifactId>asciidoctor-maven-plugin</artifactId>
            <version>2.2.1</version>
            <executions>
                <execution>
                    <id>generate-docs</id>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>process-asciidoc</goal>
                    </goals>
                    <configuration>
                        <backend>html</backend>
                        <doctype>book</doctype>
                    </configuration>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.restdocs</groupId>
                    <artifactId>spring-restdocs-asciidoctor</artifactId>
                    <version>3.0.1</version>
                </dependency>
            </dependencies>
        </plugin>
        <plugin>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>${surefire-plugin.version}</version>
            <dependencies>
                <dependency>
                    <groupId>me.fabriciorby</groupId>
                    <artifactId>maven-surefire-junit5-tree-reporter</artifactId>
                    <version>1.3.0</version>
                </dependency>
            </dependencies>
            <configuration>
                <reportFormat>plain</reportFormat>
                <systemPropertyVariables>
                    <java.util.logging.manager>org.apache.logging.log4j.jul.LogManager</java.util.logging.manager>
                    <maven.home>${maven.home}</maven.home>
                </systemPropertyVariables>
                <statelessTestsetReporter implementation="org.apache.maven.plugin.surefire.extensions.junit5.JUnit5Xml30StatelessReporter">
                    <disable>false</disable>
                    <version>3.0</version>
                    <usePhrasedFileName>false</usePhrasedFileName>
                    <usePhrasedTestSuiteClassName>true</usePhrasedTestSuiteClassName>
                    <usePhrasedTestCaseClassName>true</usePhrasedTestCaseClassName>
                    <usePhrasedTestCaseMethodName>true</usePhrasedTestCaseMethodName>
                </statelessTestsetReporter>
                <consoleOutputReporter implementation="org.apache.maven.plugin.surefire.extensions.junit5.JUnit5ConsoleOutputReporter">
                    <disable>true</disable>
                </consoleOutputReporter>
                <statelessTestsetInfoReporter implementation="org.apache.maven.plugin.surefire.extensions.junit5.JUnit5StatelessTestsetInfoTreeReporter">
                    <disable>false</disable>
                    <usePhrasedFileName>false</usePhrasedFileName>
                    <usePhrasedClassNameInRunning>true</usePhrasedClassNameInRunning>
                    <usePhrasedClassNameInTestCaseSummary>true</usePhrasedClassNameInTestCaseSummary>
                </statelessTestsetInfoReporter>
            </configuration>
        </plugin>
    </plugins>
</build>

解决方案

1. 替换@ServiceConnection,手动注入连接属性

MongoDB Atlas Local容器和Spring Boot的@ServiceConnection注解存在兼容性问题,Spring Boot无法自动识别该容器的连接详情。需要移除@ServiceConnection,改用@DynamicPropertySource手动注入连接信息:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Testcontainers
@AutoConfigureWebTestClient
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@DisplayName("Testing Movies API")
class MovieServiceIT {

    @Container
    static MongoDBAtlasLocalContainer mongoDBContainer = new MongoDBAtlasLocalContainer("mongodb/mongodb-atlas-local:8.0.3");

    // 新增动态属性配置
    @DynamicPropertySource
    static void setMongoProperties(DynamicPropertyRegistry registry) {
        // 使用副本集URL连接Atlas Local容器
        registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl);
        // 可选:指定测试数据库名
        // registry.add("spring.data.mongodb.database", () -> "movie_test_db");
    }

    // 其余代码保持不变
}

2. 等待容器完全就绪

MongoDB Atlas Local容器启动速度慢于普通MongoDB容器,需要在测试前显式等待容器就绪:

@BeforeEach
void setUp() throws IOException, InterruptedException {
    // 等待容器日志出现就绪标识
    mongoDBContainer.waitingFor(Wait.forLogMessage(".*Waiting for connections.*", 1));
    
    assertThat(mongoDBContainer.isCreated()).isTrue();
    assertThat(mongoDBContainer.isRunning()).isTrue();

    movies = DataLoadUtil.loadTestModels("resources/data/movies.json");

    moviesRepository.deleteAll()
            .thenMany(Flux.just(movies.toArray(new Movie[]{})).flatMap(moviesRepository::save))
            .blockLast();
}

3. 禁用Docker Compose自动配置(可选)

如果测试不需要使用spring-boot-docker-compose,建议在测试类中禁用,避免和Testcontainers冲突:

@SpringBootTest(
    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
    properties = "spring.boot.docker.compose.enabled=false"
)

4. 校验依赖版本兼容性

确保Spring Boot和Testcontainers版本匹配:

  • Spring Boot 3.x 对应 Testcontainers 1.19+
  • Spring Boot 2.x 需使用Testcontainers 1.18及以下兼容版本

检查pom.xml中spring-boot-testcontainers和org.testcontainers:mongodb的版本是否一致,建议统一使用Testcontainers最新稳定版。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 07:32:32