Spring Boot TestContainers 映射的端口只能在容器启动后获取

Wil*_*son 9 integration-testing automated-tests spring-data-jpa testcontainers

我正在尝试将使用 TestContainers 库的自动化测试添加到我的 Spring Boot 项目中

这是我的测试类来测试我的 jpa 存储库:

package com.ubm.mfi.repo;

import com.ubm.mfi.domain.MasterFileIndexRow;
import org.junit.ClassRule;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Testcontainers;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

@ExtendWith(SpringExtension.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Testcontainers
@ContextConfiguration(initializers = { MasterFileIndexRowRepoTest.Initializer.class })
public class MasterFileIndexRowRepoTest {

    @ClassRule
    public static PostgreSQLContainer<?> postgreSQLContainer = new PostgreSQLContainer<>("postgres:latest");

    @Autowired
    private MasterFileIndexRowRepo masterFileIndexRowRepo;

    // write test cases here
    @Test
    public void whenFindAllRows_thenSizeIsGreaterThanZero() {
        // when
        List<MasterFileIndexRow> rows = masterFileIndexRowRepo.findAll();

        // then
        assertThat(rows.size())
                .isGreaterThan(0);
    }

    static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

        @Override
        public void initialize(ConfigurableApplicationContext configurableApplicationContext) {

            TestPropertyValues
                    .of("spring.datasource.url=" + postgreSQLContainer.getJdbcUrl(),
                            "spring.datasource.username=" + postgreSQLContainer.getUsername(),
                            "spring.datasource.password=" + postgreSQLContainer.getPassword())
                    .applyTo(configurableApplicationContext.getEnvironment());

        }

    }

}
Run Code Online (Sandbox Code Playgroud)

这是我的 build.gradle 中的依赖项

testCompile "org.testcontainers:testcontainers:1.14.1"
testCompile "org.testcontainers:postgresql:1.14.1"
Run Code Online (Sandbox Code Playgroud)

运行测试时,我收到此错误: Caused by: java.lang.IllegalStateException: Mapped port can only be obtained after the container is started

据我所知,容器应该在开始测试时启动,有人知道我错过了什么吗?

小智 13

不确定它是否对 smdy 有帮助,但对我来说,在其定义解决后启动实际的测试容器解决了问题:

@Container
private static final PostgreSQLContainer DATABASE = new PostgreSQLContainer("postgres:14");

static {
    DATABASE.start();
}

// any kind of DynamicPropertySources or initializers 
// goes below and can successfully get mapped port from DATABASE.getJdbcUrl()
Run Code Online (Sandbox Code Playgroud)

  • `.start()` 也适用于 `new MSSQLServerContainer&lt;&gt;()`。但刚刚意识到(至少对于“JUnit5”),我们不应该使用“.start()”。有“@Testcontainers”和“@Container”。 (2认同)

Jen*_*der 10

您正在尝试PostgresSQLContainer用作 JUnit,ClassRule但您的使用@ExtendWith似乎表明您正在使用不支持 JUnit 4 规则的 JUnit 5 / Jupiter。

改用 JUnit 5 集成的 Testcontainers:https ://www.testcontainers.org/test_framework_integration/junit_5/

  • 或者,可以使用 JDBC 集成:https://www.testcontainers.org/modules/databases/jdbc/ (3认同)