对于最新稳定版本,请使用 Spring Framework 7.0.6spring-doc.cadn.net.cn

测试夹具的依赖注入

当您使用DependencyInjectionTestExecutionListener(默认配置)时,测试实例的依赖项将从您通过@ContextConfiguration或相关注解配置的应用上下文中注入的 Bean 获取。根据您选择的注解以及将它们放置在 setter 方法还是字段上,您可以使用 setter 注入、字段注入或两者兼用。如果您使用的是 JUnit Jupiter,还可以选择使用构造函数注入(请参阅使用SpringExtension进行依赖注入)。为了与 Spring 基于注解的注入支持保持一致,您也可以对于字段和 setter 注入使用 Spring 的@Autowired注解或来自 JSR-330 的@Inject注解。spring-doc.cadn.net.cn

对于 JUnit Jupiter 以外的测试框架,TestContext 框架不会参与测试类的实例化。因此,在测试类中对构造函数使用 @Autowired@Inject 不会产生任何效果。
尽管在生产代码中不推荐使用字段注入,但在测试代码中,字段注入实际上相当自然。这种差异的原因在于,你永远不会直接实例化你的测试类。因此,无需在测试类上调用public构造函数或setter方法。

因为 @Autowired 用于执行按类型自动装配,如果您有多个相同类型的 Bean 定义,则不能对这些特定的 Bean 依赖此方法。在这种情况下,您可以将@Autowired@Qualifier结合使用。您也可以选择将@Inject@Named结合使用。或者,如果您的测试类可以访问其ApplicationContext,则可以通过调用(例如)applicationContext.getBean("titleRepository", TitleRepository.class)来执行显式查找。spring-doc.cadn.net.cn

如果你不希望对测试实例应用依赖注入,请不要在字段或 setter 方法上使用 @Autowired@Inject 注解。或者,你也可以通过使用 @TestExecutionListeners 显式配置你的类,并从监听器列表中省略 DependencyInjectionTestExecutionListener.class,从而完全禁用依赖注入。spring-doc.cadn.net.cn

考虑在目标一节中所描述的测试../integration.html#integration-testing-goals类的场景。接下来的两个代码清单展示了在字段和 setter 方法上使用@Autowired注解的方式。所有示例代码之后会给出应用程序上下文的配置。spring-doc.cadn.net.cn

以下代码清单中的依赖注入行为并非 JUnit Jupiter 所特有。相同的依赖注入技术可以与任何受支持的测试框架结合使用。spring-doc.cadn.net.cn

以下示例调用了静态断言方法,例如 assertNotNull(), 但没有在调用前加上 Assertions。在此类情况下,请假定该方法已通过 未在示例中显示的 import static 声明正确导入。spring-doc.cadn.net.cn

第一个代码清单展示了一个基于 JUnit Jupiter 的测试类实现,该实现使用 @Autowired 进行字段注入:spring-doc.cadn.net.cn

@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 注入,如下所示:spring-doc.cadn.net.cn

@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)。以下展示了该配置:spring-doc.cadn.net.cn

<?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.hibernate5.LocalSessionFactoryBean">
		<!-- configuration elided for brevity -->
	</bean>

</beans>

如果你正在扩展一个由 Spring 提供的测试基类,而该基类恰好在其某个 setter 方法上使用了 @Autowired 注解,那么你的应用上下文中可能会定义多个该类型的 bean(例如,多个 DataSource bean)。在这种情况下,你可以重写该 setter 方法,并使用 @Qualifier 注解来指定具体的目标 bean,如下所示(但请确保同时调用父类中被重写的方法):spring-doc.cadn.net.cn

// ...

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

// ...
// ...

	@Autowired
	override fun setDataSource(@Qualifier("myDataSource") dataSource: DataSource) {
		super.setDataSource(dataSource)
	}

// ...

指定的限定符(qualifier)值用于指示要注入的具体 DataSource bean,从而将类型匹配的范围缩小到特定的 bean。该值会与相应 <qualifier> 定义中的 <bean> 声明进行匹配。如果未找到匹配的限定符声明,则会退而使用 bean 的名称作为限定符值,因此你也可以通过 bean 的名称有效地指向特定的 bean(如前所示,假设 myDataSource 是该 bean 的 id)。spring-doc.cadn.net.cn