带有动态属性源的上下文配置
Spring TestContext 框架通过 DynamicPropertyRegistry
、@DynamicPropertySource
注解和 DynamicPropertyRegistrar
API 提供对_动态_属性的支持。
动态属性源基础设施最初旨在允许将 Testcontainers 驱动的测试中的属性轻松暴露给 Spring 集成测试。然而,这些功能可用于任何形式的外部资源(其生命周期在测试的 |
优先级
动态属性的优先级高于从 @TestPropertySource
、操作系统环境、Java 系统属性加载的属性,或应用程序通过声明式使用 @PropertySource
或编程式添加的属性源。因此,动态属性可用于选择性地覆盖通过 @TestPropertySource
、系统属性源和应用程序属性源加载的属性。
DynamicPropertyRegistry
DynamicPropertyRegistry
用于向 Environment
添加_名称-值_对。值是动态的,通过 Supplier
提供,该 Supplier
仅在属性解析时才会被调用。通常,方法引用用于提供值。以下部分提供了如何使用 DynamicPropertyRegistry
的示例。
@DynamicPropertySource
与应用于类级别的
@TestPropertySource
注解不同,@DynamicPropertySource
可以应用于集成测试类中的 static
方法,以便为集成测试加载的 ApplicationContext
的 Environment
中的 PropertySources
集合添加具有动态值的属性。
集成测试类中用 @DynamicPropertySource
注解的方法必须是 static
的,并且必须接受一个 DynamicPropertyRegistry
参数。有关更多详细信息,请参阅 DynamicPropertyRegistry
的类级别 javadoc。
如果您在基类中使用 |
以下示例使用 Testcontainers 项目在 Spring ApplicationContext
之外管理 Redis 容器。托管 Redis 容器的 IP 地址和端口通过 redis.host
和 redis.port
属性提供给测试的 ApplicationContext
中的组件。这些属性可以通过 Spring 的 Environment
抽象访问,或直接注入到 Spring 管理的组件中——例如,分别通过 @Value("${redis.host}")
和 @Value("${redis.port}")
。
-
Java
-
Kotlin
@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 ...
}
@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 ...
}
DynamicPropertyRegistrar
作为在集成测试类中实现 @DynamicPropertySource
方法的替代方案,您可以将 DynamicPropertyRegistrar
API 的实现注册为测试 ApplicationContext
中的 bean。这样做允许您支持 @DynamicPropertySource
方法无法实现的额外用例。例如,由于 DynamicPropertyRegistrar
本身是 ApplicationContext
中的一个 bean,它可以与上下文中的其他 bean 交互,并注册源自这些 bean 的动态属性。
测试 ApplicationContext
中任何实现 DynamicPropertyRegistrar
接口的 bean 都将自动检测并在单例预实例化阶段之前被急切地初始化,并且这些 bean 的 accept()
方法将使用 DynamicPropertyRegistry
调用,该注册表代表注册器执行实际的动态属性注册。
与任何其他 bean 的交互都会导致这些其他 bean 及其依赖项的急切初始化。
以下示例演示了如何将 DynamicPropertyRegistrar
实现为 lambda 表达式,该表达式为 ApiServer
bean 注册动态属性。api.url
属性可以通过 Spring 的 Environment
抽象访问,或直接注入到其他 Spring 管理的组件中——例如,通过 @Value("${api.url}")
,并且 api.url
属性的值将从 ApiServer
bean 动态检索。
-
Java
-
Kotlin
@Configuration
class TestConfig {
@Bean
ApiServer apiServer() {
return new ApiServer();
}
@Bean
DynamicPropertyRegistrar apiPropertiesRegistrar(ApiServer apiServer) {
return registry -> registry.add("api.url", apiServer::getUrl);
}
}
@Configuration
class TestConfig {
@Bean
fun apiServer(): ApiServer {
return ApiServer()
}
@Bean
fun apiPropertiesRegistrar(apiServer: ApiServer): DynamicPropertyRegistrar {
return registry -> registry.add("api.url", apiServer::getUrl)
}
}