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

测试夹具的依赖注入

当你使用 DependencyInjectionTestExecutionListener(默认配置为DependencyInjectionTestExecutionListener),你的测试实例的依赖项将从你在@ContextConfiguration或相关注解中配置的应用上下文中注入。你可以使用属性注入、字段注入,或者两者都使用,这取决于你选择的注解以及你是否将它们放在setter方法或字段上。如果你正在使用JUnit Jupiter,你还可以选择性地使用构造器注入(参见使用SpringExtension进行依赖注入)。为了与Spring的注解式注入支持保持一致,你也可以使用Spring的@Autowired注解或JSR-330的@Inject注解来进行字段和setter注入。spring-doc.cadn.net.cn

For testing frameworks other than JUnit Jupiter, the TestContext framework does not participate in instantiation of the test class. Thus, the use of @Autowired or @Inject for constructors has no effect for test classes.
虽然字段注入在生产代码中不被推荐,但在测试代码中字段注入实际上是相当自然的。这种差异的原因是你永远不会直接实例化你的测试类。因此,没有必要能够在你的测试类上调用无参构造函数或setter方法。

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

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

考虑测试 HibernateTitleRepository 类的情景,如在目标部分所述。接下来的两个代码示例展示了在字段和setter方法中使用 @Autowired 的情况。所有示例代码列出后将展示应用程序上下文配置。spring-doc.cadn.net.cn

以下代码示例中的依赖注入行为并不特定于JUnit Jupiter。相同的DI技术可以与任何受支持的测试框架结合使用。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)
	}

// ...

指定的限定符值指示要注入的具体DataSource bean,将类型匹配集缩小到具体的一个bean。它的值与对应<bean>定义中的<qualifier>声明进行匹配。如果限定符没有指定,bean名称将用作默认的限定符值,因此你也可以通过名称(如前面所示,假设myDataSource是beanid)有效地指向一个具体的bean。spring-doc.cadn.net.cn