Context
I have an application (recently upgraded to Spring Boot 3.4.0) with two configured data sources, following a setup similar to the one described in this Baeldung article.
Currently, I am using Testcontainers for integration tests, based on the approach outlined in Spring Boot's documentation. These tests mock the second data source, and everything is working perfectly.
After a great initial experience using Testcontainers for testing, I decided to try it for local development. However, this is where I encountered some challenges.
Problem
I followed the steps described in Baeldung's article on Testcontainers support for local development and Spring's blog post on improved Testcontainers support in Spring Boot 3.1.
Below are the classes involved:
public interface OracleContainerConfiguration {
@Container
OracleContainer oracleContainer =
new OracleContainer("gvenzl/oracle-free:slim-faststart")
.withReuse(true);
@DynamicPropertySource
private static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("my-custom.datasource.url", oracleContainer::getJdbcUrl);
registry.add("my-custom.datasource.username", oracleContainer::getUsername);
registry.add("my-custom.datasource.password", oracleContainer::getPassword);
}
}
@TestConfiguration(proxyBeanMethods = false)
@ImportTestcontainers(OracleContainerConfiguration.class)
public class LocalDevelopmentContainersConfiguration {}
public class MyApplicationWithContainer {
public static void main(String[] args) {
SpringApplication.from(MyApplication::main)
.withAdditionalProfiles("integration-test-oracle")
.with(LocalDevelopmentContainersConfiguration.class)
.run(args);
}
}
When running the application, I noticed that the data source configuration is executed before the @DynamicPropertySource, which results in the application picking up the properties defined in my application.yml.
In contrast, during an integration test, the behavior is reversed: the values from the @DynamicPropertySource are processed first, and only then is the data source configured.
Is this the expected behavior, or could it be a bug when using Testcontainers for local development?
Please let me know if anything is unclear.
Thank you very much!
Comment From: wilkinsona
It's hard to say for sure what's happening as there are some parts of your app that you haven't shared. For example, we can't see how the my-custom.datasource.* properties are consumed. If you would like us to spend some more time investigating, please spend some time providing a complete yet minimal sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue.
Comment From: AlbertoCortina
Hello @wilkinsona, thank you for looking into the issue.
While creating a minimal example to reproduce the error, I discovered that the cause of the problem was having the dependency implementation("org.springframework.boot:spring-boot-devtools") in my build.gradle.kts. After removing it, everything worked as expected.
I'm not sure if this behavior is intentional or not. If you'd like, I have a small project where the issue can be reproduced.
Comment From: wilkinsona
Yes please, @AlbertoCortina.
Comment From: AlbertoCortina
Here is the repository -> https://github.com/AlbertoCortina/demo-bug-testcontainers-dynamicpropertysource
To reproduce the error just try to run the application in the test folder, you will see that it goes first to the data source configuration classes and the to the @DynamicPropertySource.
Please let me know if you don't manage to reproduce the error
Comment From: philwebb
Thanks for the sample, this appears to be because the H2ConsoleAutoConfiguration is triggering DataSource bean initialization from a ServletRegistrationBean. As a work around you can add the following to your application.yml:
spring:
h2:
console:
enabled: false
Comment From: quaff
Thanks for the sample, this appears to be because the
H2ConsoleAutoConfigurationis triggeringDataSourcebean initialization from aServletRegistrationBean. As a work around you can add the following to yourapplication.yml:
yaml spring: h2: console: enabled: true
It should be false to disable H2ConsoleAutoConfiguration, am I missing something?
Comment From: philwebb
@quaff Thanks. Typo on my side.