我们不是使用JUnit @ClassRule
来为我们的集成测试数据库启动docker TestContainers,而是让Spring使用ApplicationContextInitializer
s来实现。
好处:
ClassRule
使每个测试类启动一个新容器),ClassRule
中的JUnit TestSuite
)DataSource
,Session
等),我们使用相同的配置类作为生产应用程序简化示例:
public class RedisContainerInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, ApplicationListener<ContextClosedEvent> {
private GenericContainer<?> container;
@Override
public void initialize(ConfigurableApplicationContext ctx) {
container = new GenericContainer<>("redis:3.2.12-alpine").withExposedPorts(6379);
container.start();
// Inject properties
TestPropertyValues props = TestPropertyValues.of(
"spring.redis.host=" + container.getContainerIpAddress(),
"spring.redis.port=" + container.getMappedPort(6379));
props.applyTo(ctx);
// Register this object as a bean,
// so testing code can access the container
ctx.getBeanFactory().registerSingleton("redisContainer", this);
// Make this instance receive Spring context "Close" events
ctx.addApplicationListener(this);
}
@Override
public void onApplicationEvent(ContextClosedEvent event) {
container.close();
}
// getter, other irrelevant methods
}
问题:使用ApplicationContextInitializer
可行,但这是否是“春季之道”?
如果没有,那么什么样的Spring Bean可以尽早加载以注入Spring Boot启动程序将使用的属性?
在某些时候,我们使用了Spring Cloud Bootstrap上下文,但是用户不需要Spring Cloud来运行集成测试。