领先一步
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 参数静态工厂方法。例如,如果 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,@MockitoSpyBean
用于将 Bean 包装在间谍中。
这些注解中的每一个都有特定于 Mockito 的属性,以便进一步配置目标 Bean 的模拟方式。这包括支持指定测试之间如何重置模拟,如下例所示
@Configuration
class ProdConfiguration {
@Bean
MyService customService() {
return new ProdService();
}
}
@SpringJUnitConfig
class MyServiceIntegrationTests {
@MockitoSpyBean(reset = MockReset.NONE)
MyService customService;
@Test
void test() {
//...
}
}
在上面的示例中,间谍在测试之间_不会_重置。默认情况下,模拟和间谍在测试方法运行_之后_重置。
请注意,为了监视 Bean,首先必须存在被监视类的实际实例。Bean 覆盖功能支持这种情况,并且允许在 Bean 实例化后从元数据创建覆盖,这除了更常见的替换 Bean 定义的情况之外。
新的测试中 Bean 覆盖以基于注解的模型的形式出现,适用于测试类中的字段。它是可扩展和可定制的,上面介绍的 3 个注解只是我们提供的开箱即用的默认实现。
实现您自己的 Bean 覆盖风格就像实现以下内容一样简单
@BeanOverride
元注解的注解,它定义了要使用的BeanOverrideProcessor
。BeanOverrideProcessor
实现本身。OverrideMetadata
实现。Spring TestContext Framework 解析测试类,查找任何用@BeanOverride
元注解的字段,并实例化相关的BeanOverrideProcessor
以注册OverrideMetadata
实例。
然后,BeanFactoryPostProcessor
将使用这些信息来更改上下文,注册和替换每个元数据定义的 Bean 定义。
Spring TestContext Framework 现在提供了两种在测试中覆盖 Bean 的方法,而无需冒意外副作用的风险。Bean 覆盖机制是可扩展的,这在方便,例如,如果您更喜欢使用 Mockito 之外的模拟库。
我们期待社区对此功能的反馈,包括对第一次迭代的改进建议。
与此同时,祝您编码愉快!