如何使用两个不同的驱动程序重用 `testcontainers` 容器?
How to reuse a `testcontainers` container with two different drivers?
我在同一个应用程序中同时使用 r2dbc 和 Liquibase。但是,Liquibase 无法使用 r2dbc 运行 迁移,因此我需要使用单独的 jdbc 驱动程序。
我遵循解决方案 ,并使用 testcontainers 进行测试,所以我的 application-test.yaml
看起来完全像这样:
spring:
liquibase:
url: jdbc:tc:postgresql:14.1:///testdb
r2dbc:
url: r2dbc:tc:postgresql:///testdb?TC_IMAGE_TAG=14.1
这非常有效,启动了迁移,然后查询就可以 运行。问题是,这启动了两个不同的容器!因此迁移 运行 针对其中一个,而查询针对另一个,因此他们发现数据库是空的。
有什么方法可以告诉 testcontainers 对两个连接使用相同的容器。
当您使用 Testcontainers 的 JDBC support 时,您可以通过在 jdbc url 中添加 tc
来配置它,容器的生命周期是自动管理的。
因为你有两个不同的 urls 像这样检测,你得到 2 个容器。
相反,您可以选择一种不同的方式来管理生命周期,让您拥有更多的控制权。
您可以 do it yourself by creating a containers instances and calling start()/stop()
or for example use JUnit integration 将容器生命周期与测试生命周期相对应。
例如,对于 JUnit5,您将 class 标记为 @Testcontainers
,字段标记为 @Container
,例如:
@Testcontainers
class MixedLifecycleTests {
@Container
private static PostgreSQLContainer postgresqlContainer = new PostgreSQLContainer();
}
由于您正在开发 Spring 应用程序,因此您希望将其配置为使用容器,为此用途 @DynamicPropertySource
:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/context/DynamicPropertySource.html
简而言之,您用它标记一个方法并在其中配置 Spring 以使用容器中的数据库:
@DynamicPropertySource
static void redisProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgresqlContainer:: getJdbcUrl);
registry.add("spring.datasource.username", postgresqlContainer::getUsername);
registry.add("spring.datasource.password", postgresqlContainer::getPassword);
registry.add("spring.r2dbc.url", () -> "r2dbc:postgresql://"
+ postgreSQLContainer.getHost() + ":" + postgreSQLContainer.getFirstMappedPort()
+ "/" + postgreSQLContainer.getDatabaseName());
registry.add("spring.r2dbc.username", postgreSQLContainer::getUsername);
registry.add("spring.r2dbc.password", postgreSQLContainer::getPassword);
}
请注意,由于您的应用使用 r2dbc 而 Liquibase 与 non-reactive jdbc 一起使用,因此您应该同时配置两者。
我在同一个应用程序中同时使用 r2dbc 和 Liquibase。但是,Liquibase 无法使用 r2dbc 运行 迁移,因此我需要使用单独的 jdbc 驱动程序。
我遵循解决方案 application-test.yaml
看起来完全像这样:
spring:
liquibase:
url: jdbc:tc:postgresql:14.1:///testdb
r2dbc:
url: r2dbc:tc:postgresql:///testdb?TC_IMAGE_TAG=14.1
这非常有效,启动了迁移,然后查询就可以 运行。问题是,这启动了两个不同的容器!因此迁移 运行 针对其中一个,而查询针对另一个,因此他们发现数据库是空的。
有什么方法可以告诉 testcontainers 对两个连接使用相同的容器。
当您使用 Testcontainers 的 JDBC support 时,您可以通过在 jdbc url 中添加 tc
来配置它,容器的生命周期是自动管理的。
因为你有两个不同的 urls 像这样检测,你得到 2 个容器。
相反,您可以选择一种不同的方式来管理生命周期,让您拥有更多的控制权。
您可以 do it yourself by creating a containers instances and calling start()/stop()
or for example use JUnit integration 将容器生命周期与测试生命周期相对应。
例如,对于 JUnit5,您将 class 标记为 @Testcontainers
,字段标记为 @Container
,例如:
@Testcontainers
class MixedLifecycleTests {
@Container
private static PostgreSQLContainer postgresqlContainer = new PostgreSQLContainer();
}
由于您正在开发 Spring 应用程序,因此您希望将其配置为使用容器,为此用途 @DynamicPropertySource
:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/context/DynamicPropertySource.html
简而言之,您用它标记一个方法并在其中配置 Spring 以使用容器中的数据库:
@DynamicPropertySource
static void redisProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgresqlContainer:: getJdbcUrl);
registry.add("spring.datasource.username", postgresqlContainer::getUsername);
registry.add("spring.datasource.password", postgresqlContainer::getPassword);
registry.add("spring.r2dbc.url", () -> "r2dbc:postgresql://"
+ postgreSQLContainer.getHost() + ":" + postgreSQLContainer.getFirstMappedPort()
+ "/" + postgreSQLContainer.getDatabaseName());
registry.add("spring.r2dbc.username", postgreSQLContainer::getUsername);
registry.add("spring.r2dbc.password", postgreSQLContainer::getPassword);
}
请注意,由于您的应用使用 r2dbc 而 Liquibase 与 non-reactive jdbc 一起使用,因此您应该同时配置两者。