Reputation: 8728
Assume I want to integration test code relying on a JPA datasource in a Spring Boot 2.x application with a PostgreSQL testcontainer
(great tool for managing Docker containers from within test classes with one or few more lines of code). Assume further that I'm managing the ports (included in the JDBC URL) in application.properties
, e.g.
spring.datasource.url=jdbc:postgresql://user-service-postgres:5432/user_service
In the integration test I create testcontainers with
@Rule
PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer();
In a preparation method I can access the value I want to set for spring.datasource.url
with
postgreSQLContainer.getJdbcUrl()
How to tell Spring Boot in the test to use that URL instead of the one specified in application.properties
.
I'd like to stick to my property files in order to minimize changes, but I'm thankful for other approaches including an explanation why they're superior or necessary as well.
I'm using Spring Boot 2.x.
Upvotes: 3
Views: 3521
Reputation: 12021
Since Spring Framework 5.2.5 (Spring Boot 2.2.6) this setup is now even simpler as we can use the @DynamicPropertySource
annotation and don't have to write and register a custom initializer.
Assuming you use the JUnit 5 dependency of Testcontainers, your test can look like the following:
@SpringBootTest
@Testcontainers
class ExampleIntegrationTests {
@Container
static PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer();
@DynamicPropertySource
static void dataSourceProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgreSQLContainer::getJdbcUrl);
}
}
You can read more about this new feature here. I've also covered the different application properties setup ways (depending on Spring Boot and JUnit version) in a dedicated Testcontainers guide.
Upvotes: 12
Reputation: 1154
You can manually override the property from within your Spring-boot test by using ContextConfiguration
and ApplicationContextInitializer
.
Override the property - define a static inner class:
static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
TestPropertyValues
.of("spring.datasource.url=" + postgreSQLContainer.getJdbcUrl())
.applyTo(configurableApplicationContext.getEnvironment());
}
}
ApplicationContextInitializer
can be used for programmatically initializing a Spring context before context refresh. Now, wire up the context initializer class by annotating at test class level with ContextConfiguration
:
@ContextConfiguration(initializers = Initializer.class)
Docs:
Upvotes: 2