如何设置 Spring Boot based on docker 与 testcontainers 组合的本地开发环境属性?
How to setup local dev environment properties of Spring Boot based on docker compose with testcontainers?
我正在开发一项具有许多依赖项的服务,例如 Redis、PubSub、S3、ServiceC 和 ServiceD。当我在开发中遇到一个终点时,例如/data/4
,向ServiceC 发起http 请求。
因此,要使它起作用,模拟 ServiceC 的东西必须 运行。在我的例子中,它是 wiremock(因为我不能直接 运行 ServiceC,因为它也有很多依赖项)。所有这些 MockServices 都在 docker-compose-dev 文件中。
现在回答我的问题:我如何 运行 docker - 与测试容器组合,获取分配的端口,并将正确的属性设置为 WebClient
具有正确的模拟url + 端口?
在 spring 引导启动之前,我可以使用什么生命周期钩子来 运行,并且还可以配置属性?
一个缺点是开发模式下的启动时间会增加,但我无法在 docker 撰写文件中分配固定端口,因为它们可能会在开发人员的机器上使用。因此,在本地主机上为服务 url 发送 url 默认值是没有意义的。
Testcontainers 支持使用 DockerComposeContainer
class 启动 Docker Compose 开箱即用。创建此 class 的实例时,您必须公开所有容器:
@Testcontainers
public class DockerComposeTest {
@Container
public static DockerComposeContainer<?> environment =
new DockerComposeContainer<>(new File("docker-compose.yml"))
.withExposedService("database_1", 5432, Wait.forListeningPort())
.withExposedService("keycloak_1", 8080,
Wait.forHttp("/auth").forStatusCode(200)
.withStartupTimeout(Duration.ofSeconds(30)));
@Test
void dockerComposeTest() {
System.out.println(environment.getServicePort("database_1", 5432));
System.out.println(environment.getServicePort("keycloak_1", 8080));
}
}
上面的示例将 PostgreSQL 数据库和 Keycloak 映射到您计算机上的随机临时端口。等待检查通过后,您的测试将 运行 并且您可以使用 .getServicePort()
.
访问实际端口
WebClient
配置的一个可能解决方案是使用 ApplicationContextInitializer
,因为您必须在容器启动之前以某种方式定义 Spring 启动 属性:
public class PropertyInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
// static access to environment variable of the test
TestPropertyValues
.of("your_web_client_base_url=http://localhost:" + environment.getServicePort("serviceC", 8080) + "/api")
.applyTo(configurableApplicationContext);
}
}
然后您可以为您的集成测试注册初始值设定项:
@Testcontainers
@ContextConfiguration(initializers = {PropertyInitializer.class})
class DockerComposeTest {
}
作为替代方案,您也可以尝试单独模拟与外部服务的所有 HTTP 通信 with WireMock。
我正在开发一项具有许多依赖项的服务,例如 Redis、PubSub、S3、ServiceC 和 ServiceD。当我在开发中遇到一个终点时,例如/data/4
,向ServiceC 发起http 请求。
因此,要使它起作用,模拟 ServiceC 的东西必须 运行。在我的例子中,它是 wiremock(因为我不能直接 运行 ServiceC,因为它也有很多依赖项)。所有这些 MockServices 都在 docker-compose-dev 文件中。
现在回答我的问题:我如何 运行 docker - 与测试容器组合,获取分配的端口,并将正确的属性设置为 WebClient
具有正确的模拟url + 端口?
在 spring 引导启动之前,我可以使用什么生命周期钩子来 运行,并且还可以配置属性?
一个缺点是开发模式下的启动时间会增加,但我无法在 docker 撰写文件中分配固定端口,因为它们可能会在开发人员的机器上使用。因此,在本地主机上为服务 url 发送 url 默认值是没有意义的。
Testcontainers 支持使用 DockerComposeContainer
class 启动 Docker Compose 开箱即用。创建此 class 的实例时,您必须公开所有容器:
@Testcontainers
public class DockerComposeTest {
@Container
public static DockerComposeContainer<?> environment =
new DockerComposeContainer<>(new File("docker-compose.yml"))
.withExposedService("database_1", 5432, Wait.forListeningPort())
.withExposedService("keycloak_1", 8080,
Wait.forHttp("/auth").forStatusCode(200)
.withStartupTimeout(Duration.ofSeconds(30)));
@Test
void dockerComposeTest() {
System.out.println(environment.getServicePort("database_1", 5432));
System.out.println(environment.getServicePort("keycloak_1", 8080));
}
}
上面的示例将 PostgreSQL 数据库和 Keycloak 映射到您计算机上的随机临时端口。等待检查通过后,您的测试将 运行 并且您可以使用 .getServicePort()
.
WebClient
配置的一个可能解决方案是使用 ApplicationContextInitializer
,因为您必须在容器启动之前以某种方式定义 Spring 启动 属性:
public class PropertyInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
// static access to environment variable of the test
TestPropertyValues
.of("your_web_client_base_url=http://localhost:" + environment.getServicePort("serviceC", 8080) + "/api")
.applyTo(configurableApplicationContext);
}
}
然后您可以为您的集成测试注册初始值设定项:
@Testcontainers
@ContextConfiguration(initializers = {PropertyInitializer.class})
class DockerComposeTest {
}
作为替代方案,您也可以尝试单独模拟与外部服务的所有 HTTP 通信 with WireMock。