领先一步
VMware 提供培训和认证,助您加速进步。
了解更多Spring Framework 6.2.0-M1 已发布,其中包括解决一百多个问题的更改。其中包括 Spring 测试支持中的一系列新功能。
在这篇文章中,我想向您介绍其中一个新测试功能:Bean 覆盖支持。
使用 Spring TestContext Framework,您可以使用注解驱动模型轻松验证 Spring 应用程序在集成测试中的正确连接。
在单元测试中,依赖注入和 Spring 设计原则使您的代码对容器的依赖性降低,并使其更容易手动存根或模拟组件的依赖项,以便对其进行隔离测试。在集成测试中,这不那么相关,因为测试旨在涵盖组件的正确连接。尽管您可能会发现在集成测试中需要替换 bean 的情况。
Spring Framework 团队通常不建议重新定义 bean。尽管在 BeanDefinitionRegistry 的默认实现中,通过一个标志目前是可能的,但我们计划将其弃用,并且 Spring Boot 已经通过默认关闭 bean 覆盖来选择退出。
然而,这在生产代码中更受关注,我们认识到在测试中覆盖 bean 是有用且合法的。因此,我们的目标是在该领域为常见的覆盖场景提供一流的安排。
在 Spring Framework 6.2.0-M1 中,我们引入了一个可扩展的 bean 覆盖功能,它允许您在集成测试中精确且明确地替换一个或多个 bean 定义,同时防范生产代码或测试其他部分中此类意外更改。
@TestBean 进行简单的基于方法的覆盖Spring TestContext Framework 现在提供了一个简单的 Bean 覆盖支持实现:@TestBean 注解。
覆盖名为 example 的 bean 分三步完成:添加一个以 bean 命名的字段,用 @TestBean 注解它,并添加一个名为 exampleTestOverride 的 0 参数 static 工厂方法。在该工厂方法中,您可以返回一个简化实现,如果 bean 类型是一个接口,如下例所示
@Configuration
class ProdConfiguration {
@Bean
MyService customService() {
return new ProdServiceImpl();
}
}
@SpringJUnitConfig
class MyServiceIntegrationTests {
@TestBean
MyService customService;
static MyService customServiceTestOverride() {
return new SimplifiedServiceImpl();
}
@Test
void test(ApplicationContext context) {
assertThat(context.getBean("customService")
.isSameAs(this.customService)
.isInstanceOf(SimplifiedServiceImpl.class);
//...
}
}
除非向 @TestBean 注解提供了 beanName 属性,否则注解字段的名称被解释为目标 bean 的名称。
methodName 参数也可以用来指向一个不遵循 {beanName}TestOverride 默认命名约定的工厂方法。
Bean 覆盖机制负责解析此注解并替换注册表中现有的 bean 定义。测试类中的 customService 字段也注入了由 customServiceTestOverride 工厂方法生成的覆盖实例。
@MockitoBean 和 @MockitoSpyBean 进行基于 Mockito 的覆盖第二个 bean 覆盖实现基于 Mockito 库。它带有两个注解:@MockitoBean 用于自动将目标单例 bean 替换为 mock,而 @MockitoSpyBean 则用于将 bean 包装成 spy。
这些注解中的每一个都具有 Mockito 特定的属性,以便进一步配置目标 bean 的模拟方式。这包括支持指定模拟如何在测试之间重置,如下例所示
@Configuration
class ProdConfiguration {
@Bean
MyService customService() {
return new ProdService();
}
}
@SpringJUnitConfig
class MyServiceIntegrationTests {
@MockitoSpyBean(reset = MockReset.NONE)
MyService customService;
@Test
void test() {
//...
}
}
在上面的示例中,spy 在测试之间将不会被重置。默认情况下,mock 和 spy 在测试方法运行之后重置。
请注意,为了监视一个 bean,首先必须存在一个被监视类的实际实例。Bean 覆盖功能支持此特殊情况,并允许在实例化 bean 后从元数据创建覆盖,此外还有更常见的替换 bean 定义的情况。
测试中新的 Bean 覆盖支持以适用于测试类字段的基于注解的模型形式提供。它是可扩展和可定制的,上面介绍的三个注解只是我们开箱即用提供的默认实现。
实现您自己的 Bean 覆盖版本就像实现以下内容一样简单
@BeanOverride 元注解的注解,它定义要使用的 BeanOverrideProcessor。BeanOverrideProcessor 实现本身。OverrideMetadata 实现。Spring TestContext Framework 解析测试类,查找任何带有 @BeanOverride 元注解的字段,并实例化相关的 BeanOverrideProcessor 以注册 OverrideMetadata 实例。
然后,一个 BeanFactoryPostProcessor 将使用该信息来更改上下文,根据每个元数据定义注册和替换 bean 定义。
Spring TestContext Framework 现在提供了两种在测试中覆盖 bean 的方法,而没有意外副作用的风险。bean 覆盖机制是可扩展的,例如,如果您喜欢使用 Mockito 以外的模拟库,这可能会派上用场。
我们期待社区对该功能的反馈,包括对首次迭代的改进建议。
同时,祝您编码愉快!