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

自 TODAY Framework 5.2.5 起,TestContext 框架通过 @DynamicPropertySource 注解提供了对_动态_属性的支持。此注解可用于需要向为集成测试加载的 ApplicationContextEnvironment 中的 PropertySources 集合添加具有动态值的属性的集成测试。

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

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

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

@JUnitConfig(/* ... */)
@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);
  }

  // 测试 ...

}

优先级

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