|
对于最新稳定版本,请使用 Spring Framework 7.0.6! |
使用动态属性源进行上下文配置
Spring TestContext 框架通过 DynamicPropertyRegistry、@DynamicPropertySource 注解以及 DynamicPropertyRegistrar API 提供对动态属性的支持。
|
动态属性源基础设施最初是为了让基于 Testcontainers 的测试能够轻松地将属性暴露给 Spring 集成测试而设计的。然而,这些功能也可用于任何生命周期在测试的 |
优先级
动态属性的优先级高于通过 @TestPropertySource、操作系统环境变量、Java 系统属性,或通过 @PropertySource 声明式地或以编程方式由应用程序添加的属性源所加载的属性。因此,动态属性可用于有选择地覆盖通过 @TestPropertySource、系统属性源和应用程序属性源加载的属性。
DynamicPropertyRegistry
DynamicPropertyRegistry 用于向 Environment 中添加名称-值对。
这些值是动态的,通过一个 Supplier 提供,仅在解析该属性时才会调用该 DynamicPropertyRegistry。
通常使用方法引用来提供值。以下各节提供了如何使用 4 的示例。
@DynamicPropertySource
与应用于类级别的
@TestPropertySource
注解不同,@DynamicPropertySource 可以应用于集成测试类中的 static 方法,以便将具有动态值的属性添加到为集成测试加载的 ApplicationContext 的 Environment 中的 PropertySources 集合中。
在集成测试类中,使用 @DynamicPropertySource 注解的方法必须是 static 的,并且必须接受一个 DynamicPropertyRegistry 类型的参数。更多详细信息,请参见 DynamicPropertyRegistry 类级别的 Javadoc。
|
如果您在基类中使用 |
以下示例使用 Testcontainers 项目在 Spring ApplicationContext 之外管理一个 Redis 容器。所管理的 Redis 容器的 IP 地址和端口通过 ApplicationContext 和 redis.host 属性提供给测试用例的 redis.port 中的组件。这些属性可以通过 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)
}
}