The Spring TestContext Framework provides support for dynamic properties via the
@DynamicPropertySource
annotation and the DynamicPropertyRegistry
.
Note
|
The |
In contrast to the
@TestPropertySource
annotation that is applied at the class level, @DynamicPropertySource
can be applied to
static
methods in integration test classes or to @Bean
methods in test
@Configuration
classes in order to add properties with dynamic values to the set of
PropertySources
in the Environment
for the ApplicationContext
loaded for the
integration test.
A DynamicPropertyRegistry
is used to add name-value pairs to the Environment
.
Values are dynamic and provided via a Supplier
which is only invoked when the property
is resolved. Typically, method references are used to supply values.
Methods in integration test classes that are annotated with @DynamicPropertySource
must
be static
and must accept a single DynamicPropertyRegistry
argument.
@Bean
methods annotated with @DynamicPropertySource
may either accept an argument of
type DynamicPropertyRegistry
or access a DynamicPropertyRegistry
instance autowired
into their enclosing @Configuration
class. Note, however, that @Bean
methods which
interact with a DynamicPropertyRegistry
are not required to be annotated with
@DynamicPropertySource
unless they need to enforce eager initialization of the bean
within the context. See the class-level javadoc for DynamicPropertyRegistry
for details.
Tip
|
If you use |
The following example uses the Testcontainers project to manage a Redis container outside
of the Spring ApplicationContext
. The IP address and port of the managed Redis
container are made available to components within the test’s ApplicationContext
via the
redis.host
and redis.port
properties. These properties can be accessed via Spring’s
Environment
abstraction or injected directly into Spring-managed components – for
example, via @Value("${redis.host}")
and @Value("${redis.port}")
, respectively.
- Java
-
@SpringJUnitConfig(/* ... */) @Testcontainers class ExampleIntegrationTests { @Container static GenericContainer redis = new GenericContainer("redis:5.0.3-alpine").withExposedPorts(6379); @DynamicPropertySource static void redisProperties(DynamicPropertyRegistry registry) { registry.add("redis.host", redis::getHost); registry.add("redis.port", redis::getFirstMappedPort); } // tests ... }
- Kotlin
-
@SpringJUnitConfig(/* ... */) @Testcontainers class ExampleIntegrationTests { companion object { @Container @JvmStatic val redis: GenericContainer = GenericContainer("redis:5.0.3-alpine").withExposedPorts(6379) @DynamicPropertySource @JvmStatic fun redisProperties(registry: DynamicPropertyRegistry) { registry.add("redis.host", redis::getHost) registry.add("redis.port", redis::getFirstMappedPort) } } // tests ... }
The following example demonstrates how to use DynamicPropertyRegistry
and
@DynamicPropertySource
with a @Bean
method. The api.url
property can be accessed
via Spring’s Environment
abstraction or injected directly into other Spring-managed
components – for example, via @Value("${api.url}")
. The value of the api.url
property
will be dynamically retrieved from the ApiServer
bean.
- Java
-
@Configuration class TestConfig { @Bean @DynamicPropertySource ApiServer apiServer(DynamicPropertyRegistry registry) { ApiServer apiServer = new ApiServer(); registry.add("api.url", apiServer::getUrl); return apiServer; } }
- Kotlin
-
@Configuration class TestConfig { @Bean @DynamicPropertySource fun apiServer(registry: DynamicPropertyRegistry): ApiServer { val apiServer = ApiServer() registry.add("api.url", apiServer::getUrl) return apiServer } }
Note
|
The use of @DynamicPropertySource on the @Bean method is optional and results
in the ApiServer bean being eagerly initialized so that other beans in the context can
be given access to the dynamic properties sourced from the ApiServer bean when those
other beans are initialized.
|
Dynamic properties have higher precedence than those loaded from @TestPropertySource
,
the operating system’s environment, Java system properties, or property sources added by
the application declaratively by using @PropertySource
or programmatically. Thus,
dynamic properties can be used to selectively override properties loaded via
@TestPropertySource
, system property sources, and application property sources.