@TestBean
@TestBean
@TestBean被用于测试类中的非静态字段上,以便用工厂方法提供的实例来覆盖测试中的ApplicationContext中的特定Bean。
关联的工厂方法名称来源于被注释字段的名称,如果指定了的话,也可以使用Bean的名称。工厂方法必须是static(静态的),不能接受任何参数,并且其返回类型必须与要覆盖的Bean的类型兼容。为了更加明确,或者如果你希望使用不同的名称,该注解允许提供一个具体的方法名称。
默认情况下,会使用被注解字段的类型来搜索可以覆盖的候选bean。如果有多个候选bean匹配,则可以提供@Qualifier来进一步缩小需要覆盖的候选范围。或者,只要候选bean的名称与该字段的名称相匹配,即可被选中。
如果相应的bean不存在,将会创建一个新的bean。但是,如果你希望当相应的bean不存在时测试失败,你可以将enforceOverride属性设置为true——例如,@TestBean(enforceOverride = true)。
要使用按名称覆盖(by-name override)而不是按类型覆盖(by-type override),请指定注解的 name 属性。
限定符(包括字段的名称)用于确定是否需要创建一个单独的ApplicationContext。如果您使用此功能在多个测试中覆盖同一个Bean,请确保字段的命名保持一致,以避免创建不必要的上下文。
将 @TestBean 与 @ContextHierarchy 结合使用可能会导致不良结果,因为默认情况下每个 @TestBean 都会应用于所有的上下文层次结构级别。要确保某个特定的 @TestBean 仅应用于单个上下文层次结构级别,请设置 contextName 属性以匹配已配置的 @ContextConfiguration 名称——例如,@TestBean(contextName = "app-config")。
有关更多详细信息和示例,请参阅 带有 Bean 重写的上下文层次结构。
@TestBean字段或工厂方法的可见性没有任何限制。
因此,根据项目的需求或编码惯例,这些字段和方法可以是public、protected、包私有(默认可见性)或private。
以下示例展示了如何使用@TestBean注解的默认行为:
- Java
class OverrideBeanTests {
@TestBean 1
CustomService customService;
// test case body...
static CustomService customService() { 2
return new MyFakeCustomService();
}
}
标记一个需要被覆盖的
CustomService类型的字段。这个静态方法的结果将作为实例被使用,并注入到该字段中。
在上面的例子中,我们正在覆盖类型为CustomService的bean。如果存在多个该类型的bean,则会考虑名为customService的bean。否则,测试将会失败,你需要提供一种标识符来指定你想要覆盖哪一个CustomService bean。
以下示例使用的是按名称查找(by-name lookup),而不是按类型查找(by-type lookup):
- Java
class OverrideBeanTests {
@TestBean(name = "service", methodName = "createCustomService") 1
CustomService customService;
// test case body...
static CustomService createCustomService() { 2
return new MyFakeCustomService();
}
}
标记一个名为
service的字段用于覆盖该bean,并指定工厂方法的名称为createCustomService。这个静态方法的结果将作为实例被使用并注入到该字段中。
为了找到要调用的工厂方法,Spring 会在声明了 @TestBean 注解的类中、其父类中或任何实现的接口中进行查找。如果 @TestBean 注解是在一个 @Nested 测试类中声明的,那么也会搜索该嵌套类的类层次结构。
或者,也可以通过以下语法引用外部类中的工厂方法:<完全限定类名>#<方法名>——例如,methodName = "org.example.TestUtils-createCustomService"。
当覆盖一个非单例(non-singleton)bean时,该非单例bean将被替换为@TestBean工厂方法返回的值所对应的单例(singleton)bean,且相应的bean定义也会被转换为单例类型。因此,如果使用@TestBean来覆盖一个原型(prototype)或作用域(scoped)bean,那么被覆盖的bean将被视为单例bean。
类似地,当覆盖由FactoryBean创建的bean时,FactoryBean也将被替换为@TestBean工厂方法返回的值所对应的单例bean。