测试容器在一些测试后失去连接 运行

Testcontainers loss of connection after some tests running

我在我的 oss 软件中使用 testcontainer,但我认为我的配置或 docker/testcontainer 运行time...

有问题

我有一些测试,当它们 运行ning 分开时,一切正常,但是当我尝试 运行 所有测试时,由于应用程序尝试连接时出现问题,最后一次失败与容器..

调试问题我发现容器在一个端口启动,但应用程序正在尝试在另一个端口连接,大部分都在上次测试中使用 classes 运行

所有测试运行宁:

tests failing

其中一个失败的测试显示了这个日志:

log of failed test

并且当 class UserControllerTest 启动时启动的容器正在使用另一个端口,如下所示:

docker on windows showing the container port

我的测试配置是基于一个抽象的class(见下文)并且,就像所说的那样,如果 运行 class 单独显示错误,一切正常.

@Testcontainers
@ActiveProfiles("test")
@ExtendWith(SpringExtension::class)
@TestMethodOrder(value = OrderAnnotation::class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
abstract class AbstractTest {

    companion object {

        @Container
        private val redisContainer = GenericContainer<Nothing>("redis:6-alpine")
            .apply {
                withExposedPorts(6379)
                withCreateContainerCmdModifier { cmd -> cmd.withName("wb-test-cache") }
            }

        @Container
        private val postgresContainer = PostgreSQLContainer<Nothing>("postgres:13-alpine")
            .apply {
                withExposedPorts(5432)
                withUsername("sa_webbudget")
                withPassword("sa_webbudget")
                withDatabaseName("webbudget")
                withCreateContainerCmdModifier { cmd -> cmd.withName("wb-test-database") }
            }

        @JvmStatic
        @DynamicPropertySource
        fun dynamicPropertiesRegister(registry: DynamicPropertyRegistry) {
            registry.add("spring.datasource.url", postgresContainer::getJdbcUrl)
            registry.add("spring.redis.host", redisContainer::getHost)
            registry.add("spring.redis.port", redisContainer::getFirstMappedPort)
        }
    }
}

有人见过这样的事情知道如何解决吗?

您想启动容器以供重用。把它放到方法链中:

.withReuse(true);

根据文档:

Containers declared as static fields will be shared between test methods. They will be started only once before any test method is executed and stopped after the last test method has executed. Containers declared as instance fields will be started and stopped for every test method.

所以也许您正在为每个测试重新启动容器并获得新的端口号?

参见:https://www.testcontainers.org/test_framework_integration/junit_5/

我们 运行 一个类似于你想要完成的设置,但是在摘要 class 中使用 @ContextConfiguration( initializers = [ 和一个初始化列表,其中配置了每个容器并且添加到共享 ConfigurableApplicationContext。但是,如果您仅使用注释就可以使它工作,那么您的方法似乎要简单得多。

经过一些研究,我发现了问题所在:上下文。

当 spring 运行第一个 mvc 控制器测试时,它会为所有控制器启动 tomcat 的单个实例,这意味着当 testcontainers 为数据库重新创建 docker 实例时(在一个新的控制器开始测试)属性(端口,URL..)没有更新,因为 spring 将重用 tomcat 的当前实例(来自上次 mvc 测试)

解决方案:将每个测试 class 的上下文标记为脏,这将使 spring 在每次新测试 class 开始时重新创建上下文,这将触发 dynamicPropertiesRegister 正确更新属性。

我只需要将此注释 @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) 添加到我的 AbstractTest