2

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

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

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

所有测试运行:

测试失败

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

测试失败日志

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

Windows 上的 docker 显示容器端口

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

@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)
        }
    }
}

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

4

3 回答 3

0

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

.withReuse(true);
于 2021-08-09T03:23:28.303 回答
0

根据文档:

声明为静态字段的容器将在测试方法之间共享。它们只会在任何测试方法执行之前启动一次,并在最后一个测试方法执行后停止。声明为实例字段的容器将为每个测试方法启动和停止。

因此,也许您的容器会为每次测试重新启动并获得新的端口号?

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

我们运行与您想要完成的设置类似的设置,但@ContextConfiguration( initializers = [在抽象类中使用 a 和一个初始化器列表,其中每个容器都被配置并添加到 sharedConfigurableApplicationContext中。但是,如果您可以仅使用注释使其工作,您的方法似乎要简单得多。

于 2021-08-18T15:13:26.233 回答
0

经过一番研究,我弄清楚了问题所在:上下文。

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

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

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

于 2021-08-31T04:04:13.910 回答