测试夹具的依赖注入
当你使用 DependencyInjectionTestExecutionListener(默认已配置)时,测试实例的依赖项将从你使用 @ContextConfiguration 或相关注解配置的应用程序上下文中的 bean 中注入。你可以根据选择的注解以及是将其放置在 setter 方法还是字段上,使用 setter 注入、字段注入或两者都使用。如果你正在使用 JUnit Jupiter,你还可以选择使用构造函数注入(参见 使用 SpringExtension 进行依赖注入)。为了与 Spring 基于注解的注入支持保持一致,你也可以使用 Spring 的 @Autowired 注解或 JSR-330 的 @Inject 注解进行字段和 setter 注入。
|
对于 JUnit Jupiter 以外的测试框架,TestContext 框架不参与测试类的实例化。因此,对于测试类,在构造函数上使用 |
|
尽管在生产代码中不鼓励使用字段注入,但字段注入在测试代码中实际上非常自然。这种差异的理由是你永远不会直接实例化你的测试类。因此,没有必要在你的测试类上调用 |
因为 @Autowired 用于执行 按类型自动装配,所以如果你的应用程序上下文中存在相同类型的多个 bean 定义,你不能依赖这种方法来处理这些特定的 bean。在这种情况下,你可以将 @Autowired 与 @Qualifier 结合使用。你也可以选择将 @Inject 与 @Named 结合使用。另外,如果你的测试类可以访问其 ApplicationContext,你可以通过(例如)调用 applicationContext.getBean("titleRepository", TitleRepository.class) 来执行显式查找。
如果你不想将依赖注入应用于你的测试实例,请不要使用 @Autowired 或 @Inject 注解字段或 setter 方法。或者,你可以通过使用 @TestExecutionListeners 明确配置你的类并从监听器列表中省略 DependencyInjectionTestExecutionListener.class 来完全禁用依赖注入。
考虑测试 HibernateTitleRepository 类的场景,如 目标 部分所述。接下来的两个代码清单演示了在字段和 setter 方法上使用 @Autowired。应用程序上下文配置将在所有示例代码清单之后呈现。
|
以下代码清单中的依赖注入行为并非 JUnit Jupiter 特有。相同的 DI 技术可以与任何受支持的测试框架结合使用。
以下示例调用了静态断言方法,例如 |
第一个代码清单显示了一个基于 JUnit Jupiter 的测试类实现,该类使用 @Autowired 进行字段注入:
-
Java
-
Kotlin
@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);
}
}
@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
lateinit var titleRepository: HibernateTitleRepository
@Test
fun findById() {
val title = titleRepository.findById(10)
assertNotNull(title)
}
}
或者,你可以将类配置为使用 @Autowired 进行 setter 注入,如下所示:
-
Java
-
Kotlin
@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);
}
}
@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
lateinit var titleRepository: HibernateTitleRepository
@Autowired
fun setTitleRepository(titleRepository: HibernateTitleRepository) {
this.titleRepository = titleRepository
}
@Test
fun findById() {
val title = titleRepository.findById(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>
|
如果你正在扩展一个恰好在其某个 setter 方法上使用 |
- Java
-
// ... @Autowired @Override public void setDataSource(@Qualifier("myDataSource") DataSource dataSource) { super.setDataSource(dataSource); } // ... - Kotlin
-
// ... @Autowired override fun setDataSource(@Qualifier("myDataSource") dataSource: DataSource) { super.setDataSource(dataSource) } // ...
指定的限定符值指示要注入的特定 DataSource bean,将类型匹配集缩小到特定 bean。其值与相应 <bean> 定义中的 <qualifier> 声明进行匹配。bean 名称用作回退限定符值,因此你也可以通过名称有效地指向特定的 bean(如前所示,假设 myDataSource 是 bean id)。