当你使用 DependencyInjectionTestExecutionListener(默认配置)时,你的测试实例的依赖关系从你用 @ContextConfiguration 或相关注解配置的应用上下文中的 Bean 注入。你可以使用 setter 注入、字段注入或两者兼而有之,这取决于你选择哪种注解,以及你是把它们放在 setter 方法还是字段上。如果你使用 JUnit Jupiter,你也可以选择使用构造器注入(见 SpringExtension 的依赖注入)。为了与 Spring 基于注解的注入支持保持一致,你也可以使用 Spring 的 @Autowired 注解或来自 JSR-330 的 @Inject 注解进行字段和 setter 注入。

    :::tips 对于 JUnit Jupiter 以外的测试框架,TestContext 框架不参与测试类的实例化。因此,对构造函数使用 @Autowired 或 @Inject 对测试类没有影响。 ::: :::info 尽管在生产代码中不鼓励字段注入,但字段注入在测试代码中其实是很自然的。这种区别的理由是你永远不会直接实例化你的测试类。因此,没有必要能够在你的测试类上调用公共构造函数或 setter 方法。 :::

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

    如果你不希望依赖性注入应用于你的测试实例,不要用 @Autowired 或 @Inject 来注解字段或 setter 方法。另外,你可以通过明确地用 @TestExecutionListeners 配置你的类,并从监听器列表中省略 DependencyInjectionTestExecutionListener.class 来完全禁用依赖注入。

    考虑测试 HibernateTitleRepository 类的情景,如目标部分所述。接下来的两个代码列表演示了 @Autowired 在字段和 setter 方法上的使用。应用上下文配置在所有示例代码列表之后呈现。

    :::info 以下代码列表中的依赖注入行为并不是针对 JUnit Jupiter 的。同样的 DI 技术可以与任何支持的测试框架一起使用。

    下面的例子对静态断言方法进行了调用,例如 assertNotNull(),但没有在调用前加上 Assertions。在这种情况下,假设该方法是通过导入静态声明正确导入的,该声明在例子中没有显示。 :::

    第一个代码清单显示了一个基于 JUnit Jupiter 的测试类的实现,它使用 @Autowired 进行字段注入。

    1. @ExtendWith(SpringExtension.class)
    2. // 指定为该测试夹具加载的 Spring 配置。
    3. @ContextConfiguration("repository-config.xml")
    4. class HibernateTitleRepositoryTests {
    5. // this instance will be dependency injected by type
    6. @Autowired
    7. HibernateTitleRepository titleRepository;
    8. @Test
    9. void findById() {
    10. Title title = titleRepository.findById(new Long(10));
    11. assertNotNull(title);
    12. }
    13. }

    另外,你也可以配置类,使其使用 @Autowired 进行 setter 注入,如下所示。

    1. @ExtendWith(SpringExtension.class)
    2. // specifies the Spring configuration to load for this test fixture
    3. @ContextConfiguration("repository-config.xml")
    4. class HibernateTitleRepositoryTests {
    5. // this instance will be dependency injected by type
    6. HibernateTitleRepository titleRepository;
    7. @Autowired
    8. void setTitleRepository(HibernateTitleRepository titleRepository) {
    9. this.titleRepository = titleRepository;
    10. }
    11. @Test
    12. void findById() {
    13. Title title = titleRepository.findById(new Long(10));
    14. assertNotNull(title);
    15. }
    16. }

    前面的代码列表使用了由 @ContextConfiguration 注解引用的同一个 XML 上下文文件(也就是 repository-config.xml)。下面显示了这个配置。

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://www.springframework.org/schema/beans
    5. https://www.springframework.org/schema/beans/spring-beans.xsd">
    6. <!-- this bean will be injected into the HibernateTitleRepositoryTests class -->
    7. <bean id="titleRepository" class="com.foo.repository.hibernate.HibernateTitleRepository">
    8. <property name="sessionFactory" ref="sessionFactory"/>
    9. </bean>
    10. <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    11. <!-- configuration elided for brevity -->
    12. </bean>
    13. </beans>

    1. <br />如果你是从一个 Spring 提供的测试基类中扩展出来的,而这个基类恰好在它的一个 setter 方法上使用了 @Autowired,你可能在你的应用环境中定义了多个受影响类型的 bean(例如,多个 DataSource Bean)。在这种情况下,你可以覆盖 setter 方法,并使用 @Qualifier 注解来表示特定的目标 Bean,如下所示(但要确保在超类中也委托给被覆盖的方法):
    1. // ...
    2. @Autowired
    3. @Override
    4. public void setDataSource(@Qualifier("myDataSource") DataSource dataSource) {
    5. super.setDataSource(dataSource);
    6. }
    7. // ...

    指定的限定符值表示要注入的特定 DataSource bean,将类型匹配的范围缩小到特定的 bean。其值与相应的 <bean>定义中的 <qualifier>声明相匹配。Bean 名称被用作后备限定符值,所以你也可以有效地通过名称指向特定的 Bean(如前面所示,假设 myDataSource 是 Bean的 ID)。