使用动态属性源进行上下文配置

从Spring Framework 5.2.5开始,TestContext框架通过@DynamicPropertySource注解提供对动态属性的支持。该注解可用于需要向集成测试中加载的ApplicationContextEnvironmentPropertySources中添加具有动态值的属性。

@DynamicPropertySource注解及其支持基础设施最初设计用于轻松将基于Testcontainers的测试中的属性暴露给Spring集成测试。但是,此功能也可用于任何在测试的ApplicationContext之外维护生命周期的外部资源。

@TestPropertySource注解相比, @DynamicPropertySource必须应用于接受单个 DynamicPropertyRegistry参数的 static方法,该参数用于向 Environment添加 名称-值对。值是动态的,并通过 Supplier提供,仅在解析属性时才调用。通常,使用方法引用来提供值,如下例所示,该示例使用Testcontainers项目来管理Spring ApplicationContext之外的Redis容器。托管的Redis容器的IP地址和端口通过 redis.hostredis.port属性提供给测试的 ApplicationContext中的组件。这些属性可以通过Spring的 Environment抽象访问,或直接注入到Spring管理的组件中 - 例如,通过 @Value("${redis.host}")@Value("${redis.port}")

如果在基类中使用@DynamicPropertySource,并发现子类中的测试失败,因为动态属性在子类之间发生变化,您可能需要使用@DirtiesContext注解基类,以确保每个子类都获得具有正确动态属性的自己的ApplicationContext

  • 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 ...

}

优先级

动态属性比从@TestPropertySource、操作系统环境、Java系统属性或通过@PropertySource或编程方式添加的属性源加载的属性具有更高的优先级。因此,动态属性可用于有选择地覆盖通过@TestPropertySource、系统属性源和应用程序属性源加载的属性。