使用动态属性源进行上下文配置
Spring TestContext 框架通过DynamicPropertyRegistry
、@DynamicPropertySource
注解和DynamicPropertyRegistrar
API 提供对动态属性的支持。
动态属性源基础结构最初旨在允许来自基于Testcontainers 的测试的属性轻松地暴露给 Spring 集成测试。但是,这些功能可以与任何形式的外部资源一起使用,这些资源的生命周期在测试的 |
优先级
动态属性比从@TestPropertySource
、操作系统的环境、Java 系统属性或应用程序通过使用@PropertySource
或以编程方式声明性地添加的属性源加载的属性具有更高的优先级。因此,动态属性可用于有选择地覆盖通过@TestPropertySource
、系统属性源和应用程序属性源加载的属性。
DynamicPropertyRegistry
DynamicPropertyRegistry
用于向Environment
添加名称-值对。值是动态的,并通过Supplier
提供,只有在解析属性时才会调用该Supplier
。通常,方法引用用于提供值。以下部分提供如何使用DynamicPropertyRegistry
的示例。
@DynamicPropertySource
与应用于类级别的@TestPropertySource
注解相反,@DynamicPropertySource
可以应用于集成测试类中的static
方法,以便向Environment
中ApplicationContext
的PropertySources
集合添加具有动态值的属性(为集成测试加载的ApplicationContext
)。
用@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
实现为注册ApiServer
Bean 的动态属性的 lambda 表达式。可以通过 Spring 的Environment
抽象访问api.url
属性,或者直接注入到其他 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)
}
}