跳到主要内容
版本:7.0.3

测试 fixture 的依赖注入

Hunyuan 7b 中英对照 Dependency Injection of Test Fixtures

当你使用DependencyInjectionTestExecutionListener(默认情况下已配置好)时,测试实例的依赖项会从应用上下文中的Bean中注入,这些Bean是通过@ContextConfiguration或相关注解进行配置的。你可以根据所选择的注解类型,以及是将这些注解放在setter方法上还是字段上来决定使用setter注入、字段注入,或者两者结合使用。如果你使用的是JUnit Jupiter,还可以选择使用构造函数注入(详见[support-classes.md#testcontext-junit-jupiter-di]中的“SpringExtension下的依赖注入”)。为了与Spring基于注解的注入支持保持一致,你也可以使用Spring的@Autowired注解,或者JSR-330标准中的@Inject注解来进行字段和setter注入。

提示

对于JUnit Jupiter以外的测试框架,TestContext框架不会参与测试类的实例化过程。因此,在构造函数上使用@Autowired@Inject注解对测试类无效。

备注

虽然在生产代码中不鼓励使用字段注入(field injection),但在测试代码中使用它其实是很自然的。之所以有这种区别,是因为你永远不会直接实例化测试类(test class)。因此,没有必要能够调用测试类的public构造函数或setter方法。

因为@Autowired是用来执行按类型自动装配的,所以如果你有多个相同类型的bean定义,你不能依赖这种自动装配的方式来处理这些bean。在这种情况下,你可以将@Autowired@Qualifier结合使用。你也可以选择将@Inject@Named结合使用。另外,如果你的测试类能够访问到它的ApplicationContext,你可以通过调用applicationContext.getBean("titleRepository", TitleRepository.class)等方式来进行显式的查找。

如果您不希望将依赖注入应用到测试实例上,请不要在字段或setter方法上标注@Autowired@Inject。或者,您可以通过显式配置类并使用@TestExecutionListeners来完全禁用依赖注入,同时从监听器列表中省略DependencyInjectionTestExecutionListener.class

考虑测试一个HibernateTitleRepository类的场景,如目标部分所概述的。接下来的两个代码示例展示了如何在字段和setter方法上使用@Autowired注解。所有示例代码之后会展示应用程序上下文配置。

备注

以下代码示例中的依赖注入行为并非 JUnit Jupiter 所特有。相同的依赖注入(DI)技术可以与其他任何受支持的测试框架结合使用。

在以下示例中,调用了诸如 assertNotNull() 这样的静态断言方法,但没有在方法调用前加上 Assertions。在这种情况下,可假设该方法是通过 import static 语句正确导入的,而示例中并未显示这一导入语句。

第一个代码示例展示了一个基于JUnit Jupiter的测试类实现,该实现使用@Autowired来进行字段注入:

@ExtendWith(SpringExtension.class)
// specifies the Spring configuration to load for this test fixture
@ContextConfiguration("repository-config.xml")
class HibernateTitleRepositoryTests {

// this instance will be dependency injected by type
@Autowired
HibernateTitleRepository titleRepository;

@Test
void findById() {
Title title = titleRepository.findById(new Long(10));
assertNotNull(title);
}
}

或者,你可以配置类以使用@Autowired进行setter注入,如下所示:

@ExtendWith(SpringExtension.class)
// specifies the Spring configuration to load for this test fixture
@ContextConfiguration("repository-config.xml")
class HibernateTitleRepositoryTests {

// this instance will be dependency injected by type
HibernateTitleRepository titleRepository;

@Autowired
void setTitleRepository(HibernateTitleRepository titleRepository) {
this.titleRepository = titleRepository;
}

@Test
void findById() {
Title title = titleRepository.findById(new Long(10));
assertNotNull(title);
}
}

前面的代码示例使用了由@ContextConfiguration注解引用的同一个XML配置文件(即repository-config.xml)。以下展示了该配置内容:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- this bean will be injected into the HibernateTitleRepositoryTests class -->
<bean id="titleRepository" class="com.foo.repository.hibernate.HibernateTitleRepository">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>

<bean id="sessionFactory" class="org.springframework.orm.jpa.hibernate.LocalSessionFactoryBean">
<!-- configuration elided for brevity -->
</bean>

</beans>
备注

如果你是从Spring提供的测试基类进行扩展的,而该基类的某个setter方法中使用了@Autowired注解,那么在你的应用程序上下文中可能会定义多个相同类型的bean(例如,多个DataSource bean)。在这种情况下,你可以重写这个setter方法,并使用@Qualifier注解来指定一个特定的目标bean,如下所示(但也要确保同时调用父类中的重写方法):

// ...

@Autowired
@Override
public void setDataSource(@Qualifier("myDataSource") DataSource dataSource) {
_super.setDataSource(dataSource);
}

// ...

指定的@Qualifier值用于指示要注入的特定DataSource bean,从而将类型匹配的范围缩小到特定的bean。这个值会与相应的<bean>定义中的<qualifier>声明进行匹配。如果无法通过@Qualifier匹配到目标bean,那么会使用bean的名称作为备用匹配方式,因此你也可以通过bean的名称来指定特定的bean(如前所述,假设myDataSource就是该bean的id)。