在testcontainer启动之后,如何覆盖集成测试中application.properties中定义的端口?

时间:2019-05-03 19:06:37

标签: java spring spring-boot testcontainers

假设我想依靠PostgreSQL testcontainer将Spring Boot 2.x应用程序中依赖JPA数据源的测试代码集成在一起(使用一或几行代码从测试类中管理Docker容器的绝佳工具)。进一步假设我正在管理application.properties中的端口(包括在JDBC URL中),例如

spring.datasource.url=jdbc:postgresql://user-service-postgres:5432/user_service

在集成测试中,我使用以下方式创建测试容器

@Rule
PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer();

在准备方法中,我可以使用

访问要为spring.datasource.url设置的值
postgreSQLContainer.getJdbcUrl()

如何在测试中告诉Spring Boot使用该URL而不是application.properties中指定的URL。

我想坚持使用我的属性文件以最小化更改,但是我感谢其他方法,包括解释为什么它们也很出色或必要的原因。

我正在使用Spring Boot 2.x。

2 个答案:

答案 0 :(得分:2)

从Spring Framework 5.2.5(Spring Boot 2.2.6)开始,此设置现在变得更加简单,因为我们可以使用@DynamicPropertySource批注,而不必编写和注册自定义初始化程序。

假设您使用的是Testcontainers的JUnit 5依赖项,那么您的测试将如下所示:

@SpringBootTest
@Testcontainers
class ExampleIntegrationTests {

    @Container
    static PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer();

    @DynamicPropertySource
    static void dataSourceProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgreSQLContainer::getJdbcUrl);
    }

}

您可以阅读有关此新功能here的更多信息。我还在dedicated Testcontainers guide中介绍了不同的应用程序属性设置方式(取决于Spring Boot和JUnit版本)。

答案 1 :(得分:1)

您可以使用ContextConfigurationApplicationContextInitializer在Spring-boot测试中手动覆盖属性。

覆盖属性-定义一个静态内部类:

  static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
      TestPropertyValues
          .of("spring.datasource.url=" + postgreSQLContainer.getJdbcUrl())
          .applyTo(configurableApplicationContext.getEnvironment());
    }
  }

ApplicationContextInitializer可用于在上下文刷新之前以编程方式初始化Spring上下文。现在,通过在测试类级别使用ContextConfiguration进行注释来连接上下文初始化器类:

@ContextConfiguration(initializers = Initializer.class)

文档:

ApplicationContextInitializer

ContextConfiguration