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

TestContext Framework Support Classes

本节描述了支持 Spring TestContext 框架的各种类。spring-doc.cadn.net.cn

Spring JUnit 4 Runner

Spring TestContext框架通过自定义运行器(在JUnit 4.12或更高版本中支持)提供了与JUnit 4的全面集成。通过使用@RunWith(SpringJUnit4ClassRunner.class)或较短的@RunWith(SpringRunner.class)注解测试类,开发人员可以实现标准的基于JUnit 4的单元和集成测试,并同时享受TestContext框架的好处,例如支持加载应用程序上下文、测试实例的依赖注入、事务性测试方法执行等。如果你想使用Spring TestContext框架与替代运行器(如JUnit 4的Parameterized运行器)或第三方运行器(如MockitoJUnitRunner),你可以选择使用Spring对JUnit规则的支持spring-doc.cadn.net.cn

以下代码示例展示了配置一个使用自定义Spring Runner运行的测试类的最低要求:spring-doc.cadn.net.cn

@RunWith(SpringRunner.class)
@TestExecutionListeners({})
public class SimpleTest {

	@Test
	public void testMethod() {
		// test logic...
	}
}
@RunWith(SpringRunner::class)
@TestExecutionListeners
class SimpleTest {

	@Test
	fun testMethod() {
		// test logic...
	}
}

在前面的例子中,@TestExecutionListeners 配置了一个空列表,以禁用默认监听器,否则需要通过 @ContextConfiguration 配置一个 ApplicationContextspring-doc.cadn.net.cn

Spring JUnit 4 规则

The org.springframework.test.context.junit4.rules 包提供了以下 JUnit 4 规则(支持 JUnit 4.12 或更高版本):spring-doc.cadn.net.cn

SpringClassRule 是一个 JUnit TestRule,它支持 Spring TestContext Framework 的类级别特性,而 SpringMethodRule 是一个 JUnit MethodRule,它支持 Spring TestContext Framework 的实例级别和方法级别特性。spring-doc.cadn.net.cn

SpringRunner不同,Spring的基于规则的JUnit支持具有独立于任何org.junit.runner.Runner实现的优势,因此可以与现有的替代运行器(例如JUnit 4的Parameterized)或第三方运行器(例如MockitoJUnitRunner)结合使用。spring-doc.cadn.net.cn

要支持TestContext框架的全部功能,您必须将SpringClassRuleSpringMethodRule结合使用。以下示例展示了在集成测试中正确声明这些规则的方式:spring-doc.cadn.net.cn

// Optionally specify a non-Spring Runner via @RunWith(...)
@ContextConfiguration
public class IntegrationTest {

	@ClassRule
	public static final SpringClassRule springClassRule = new SpringClassRule();

	@Rule
	public final SpringMethodRule springMethodRule = new SpringMethodRule();

	@Test
	public void testMethod() {
		// test logic...
	}
}
// Optionally specify a non-Spring Runner via @RunWith(...)
@ContextConfiguration
class IntegrationTest {

	@Rule
	val springMethodRule = SpringMethodRule()

	@Test
	fun testMethod() {
		// test logic...
	}

	companion object {
		@ClassRule
		val springClassRule = SpringClassRule()
	}
}

JUnit 4 支持类

The org.springframework.test.context.junit4 包提供了以下支持类,用于基于 JUnit 4 的测试用例(在 JUnit 4.12 或更高版本中受支持):spring-doc.cadn.net.cn

AbstractJUnit4SpringContextTests 是一个抽象的基础测试类,它将 Spring TestContext Framework 与显式的 ApplicationContext 测试支持集成在一个 JUnit 4 环境中。当你扩展 AbstractJUnit4SpringContextTests 时,你可以访问一个 protected applicationContext 实例变量,你可以使用它来执行显式的 bean 查找或测试上下文的整体状态。spring-doc.cadn.net.cn

AbstractTransactionalJUnit4SpringContextTests 是一个抽象的事务性扩展,它为 JDBC 访问添加了一些便利功能。此类期望在 ApplicationContext 中定义一个 javax.sql.DataSource bean 和一个 PlatformTransactionManager bean。当你扩展 AbstractTransactionalJUnit4SpringContextTests 时,你可以访问一个 protected jdbcTemplate 实例变量,你可以使用该变量来执行 SQL 语句以查询数据库。你可以使用这些查询在运行与数据库相关的应用程序代码之前和之后确认数据库状态,并且 Spring 确保这些查询在与应用程序代码相同的事务范围内运行。AbstractJUnit4SpringContextTests 需要一个 javax.sql.DataSource bean 和一个 PlatformTransactionManager bean。当你扩展 AbstractTransactionalJUnit4SpringContextTests 时,你可以访问一个 protected jdbcTemplate 实例变量,用于运行 SQL 语句来查询数据库。你可以使用这些查询来确认数据库状态。Spring 确保这些查询与应用程序代码在同一事务范围内运行。当与 ORM 工具结合使用时,请确保避免 误报。如 JDBC 测试支持 中提到的那样,AbstractTransactionalJUnit4SpringContextTests 还提供了便利方法,这些方法通过使用上述的 jdbcTemplate 委托到 JdbcTestUtils 中的方法。此外,AbstractTransactionalJUnit4SpringContextTests 提供了一个针对配置的 DataSourceexecuteSqlScript(..) 方法。当与 ORM 工具结合使用时,请务必避免 误报。你可以在运行数据库相关应用程序代码之前和之后使用此类查询。AbstractTransactionalJUnit4SpringContextTests 还提供了一些委托给 JdbcTestUtils 中的方法。AbstractTransactionalJUnit4SpringContextTests 还提供了一个用于针对配置的 DataSource 运行 SQL 脚本。spring-doc.cadn.net.cn

这些类是为了方便扩展。如果你不希望你的测试类依赖于Spring特定的类层次结构,你可以通过使用@RunWith(SpringRunner.class)Spring的JUnit规则来配置你自己的自定义测试类。

Spring扩展用于JUnit Jupiter

Spring TestContext框架提供了与JUnit Jupiter测试框架的全面集成,该框架在JUnit 5中引入。通过使用@ExtendWith(SpringExtension.class)注解测试类,您可以实现标准的JUnit Jupiter单元和集成测试,并同时享受TestContext框架的好处,例如支持加载应用程序上下文、测试实例的依赖注入、事务性测试方法执行等。spring-doc.cadn.net.cn

此外,由于 JUnit Jupiter 中丰富的扩展 API,Spring 提供了以下功能,这些功能超出了 Spring 对 JUnit 4 和 TestNG 支持的功能集:spring-doc.cadn.net.cn

以下代码示例展示了如何配置一个测试类以使用SpringExtension@ContextConfiguration结合使用:spring-doc.cadn.net.cn

// Instructs JUnit Jupiter to extend the test with Spring support.
@ExtendWith(SpringExtension.class)
// Instructs Spring to load an ApplicationContext from TestConfig.class
@ContextConfiguration(classes = TestConfig.class)
class SimpleTests {

	@Test
	void testMethod() {
		// test logic...
	}
}
// Instructs JUnit Jupiter to extend the test with Spring support.
@ExtendWith(SpringExtension::class)
// Instructs Spring to load an ApplicationContext from TestConfig::class
@ContextConfiguration(classes = [TestConfig::class])
class SimpleTests {

	@Test
	fun testMethod() {
		// test logic...
	}
}

Since you can also use annotations in JUnit 5 as meta-annotations, Spring provides the @SpringJUnitConfig and @SpringJUnitWebConfig composed annotations to simplify the configuration of the test ApplicationContext and JUnit Jupiter.spring-doc.cadn.net.cn

以下示例使用 @SpringJUnitConfig 来减少前一个示例中使用的配置量:spring-doc.cadn.net.cn

// Instructs Spring to register the SpringExtension with JUnit
// Jupiter and load an ApplicationContext from TestConfig.class
@SpringJUnitConfig(TestConfig.class)
class SimpleTests {

	@Test
	void testMethod() {
		// test logic...
	}
}
// Instructs Spring to register the SpringExtension with JUnit
// Jupiter and load an ApplicationContext from TestConfig.class
@SpringJUnitConfig(TestConfig::class)
class SimpleTests {

	@Test
	fun testMethod() {
		// test logic...
	}
}

Similarly, the following example uses @SpringJUnitWebConfig to create a WebApplicationContext for use with JUnit Jupiter: 同样,以下示例使用 @SpringJUnitWebConfig 来创建一个 WebApplicationContext 用于 JUnit Jupiter:spring-doc.cadn.net.cn

// Instructs Spring to register the SpringExtension with JUnit
// Jupiter and load a WebApplicationContext from TestWebConfig.class
@SpringJUnitWebConfig(TestWebConfig.class)
class SimpleWebTests {

	@Test
	void testMethod() {
		// test logic...
	}
}
// Instructs Spring to register the SpringExtension with JUnit
// Jupiter and load a WebApplicationContext from TestWebConfig::class
@SpringJUnitWebConfig(TestWebConfig::class)
class SimpleWebTests {

	@Test
	fun testMethod() {
		// test logic...
	}
}

请参阅 @SpringJUnitConfig@SpringJUnitWebConfigSpring JUnit Jupiter 测试注解 中的文档以获取更多详细信息。spring-doc.cadn.net.cn

依赖注入与SpringExtension

SpringExtension 实现了 ParameterResolver JUnit Jupiter 扩展 API,这使得 Spring 可以为测试构造函数、测试方法和测试生命周期回调方法提供依赖注入。spring-doc.cadn.net.cn

Specifically, SpringExtension 可以从测试的 ApplicationContext 注入依赖到使用 @BeforeAll, @AfterAll, @BeforeEach, @AfterEach, @Test, @RepeatedTest, @ParameterizedTest, 以及其他注解标注的测试构造函数和方法中。spring-doc.cadn.net.cn

构造器注入

如果JUnit Jupiter测试类的构造函数中的特定参数是类型 ApplicationContext(或其子类型)或被注解或元注解为 @Autowired@Qualifier@Value,Spring会将该特定参数的值注入相应的bean或从测试的ApplicationContext中获取的值。spring-doc.cadn.net.cn

Spring 也可以配置为自动装配测试类构造函数的所有参数,如果该构造函数被认为是可自动装配的。一个构造函数被认为是可自动装配的,如果满足以下条件之一(按优先级顺序)。spring-doc.cadn.net.cn

请参阅 @TestConstructor 了解有关使用 @TestConstructor 的详细信息以及如何更改全局 测试构造器自动装配模式spring-doc.cadn.net.cn

如果测试类的构造函数被认为是自动装配的,Spring会负责解析构造函数中所有参数的参数。因此,没有其他ParameterResolver与JUnit Jupiter注册可以解析此类构造函数的参数。

Constructor injection for test classes must not be used in conjunction with JUnit Jupiter’s @TestInstance(PER_CLASS) support if @DirtiesContext is used to close the test’s ApplicationContext before or after test methods.spring-doc.cadn.net.cn

原因是 @TestInstance(PER_CLASS) 指示 JUnit Jupiter 在测试方法调用之间缓存测试实例。因此,测试实例将保留最初从已关闭的 ApplicationContext 中注入的 bean 的引用。由于测试类的构造函数在这种情况下只会被调用一次,因此依赖注入不会再发生,后续测试将与来自已关闭的 ApplicationContext 的 bean 交互,这可能会导致错误。spring-doc.cadn.net.cn

要使用 @DirtiesContext 在 "before test method" 或 "after test method" 模式下与 @TestInstance(PER_CLASS) 结合使用,必须配置 Spring 依赖项通过字段或 setter 注入提供,以便它们可以在测试方法调用之间重新注入。spring-doc.cadn.net.cn

在以下示例中,Spring 从 TestConfig.class 加载的 ApplicationContext 中注入 OrderService bean 到 OrderServiceIntegrationTests 构造函数中。spring-doc.cadn.net.cn

@SpringJUnitConfig(TestConfig.class)
class OrderServiceIntegrationTests {

	private final OrderService orderService;

	@Autowired
	OrderServiceIntegrationTests(OrderService orderService) {
		this.orderService = orderService;
	}

	// tests that use the injected OrderService
}
@SpringJUnitConfig(TestConfig::class)
class OrderServiceIntegrationTests @Autowired constructor(private val orderService: OrderService){
	// tests that use the injected OrderService
}

请注意,此功能允许测试依赖项为final,因此是不可变的。spring-doc.cadn.net.cn

如果 spring.test.constructor.autowire.mode 属性设置为 all(参见 @TestConstructor),我们可以在之前的示例中省略构造函数中的 @Autowired 声明,结果如下。spring-doc.cadn.net.cn

@SpringJUnitConfig(TestConfig.class)
class OrderServiceIntegrationTests {

	private final OrderService orderService;

	OrderServiceIntegrationTests(OrderService orderService) {
		this.orderService = orderService;
	}

	// tests that use the injected OrderService
}
@SpringJUnitConfig(TestConfig::class)
class OrderServiceIntegrationTests(val orderService:OrderService) {
	// tests that use the injected OrderService
}

方法注入

如果JUnit Jupiter测试方法或测试生命周期回调方法中的参数是类型ApplicationContext(或其子类型)或被注解@Autowired@Qualifier@Value(或元注解),Spring会为该特定参数注入来自测试的ApplicationContext中的相应bean。spring-doc.cadn.net.cn

在以下示例中,Spring 从 TestConfig.class 中加载的 ApplicationContext 注入到 deleteOrder() 测试方法中:spring-doc.cadn.net.cn

@SpringJUnitConfig(TestConfig.class)
class OrderServiceIntegrationTests {

	@Test
	void deleteOrder(@Autowired OrderService orderService) {
		// use orderService from the test's ApplicationContext
	}
}
@SpringJUnitConfig(TestConfig::class)
class OrderServiceIntegrationTests {

	@Test
	fun deleteOrder(@Autowired orderService: OrderService) {
		// use orderService from the test's ApplicationContext
	}
}

由于JUnit Jupiter中对ParameterResolver的支持非常强大,你还可以在一个方法中注入多个依赖,不仅来自Spring,还来自JUnit Jupiter本身或其他第三方扩展。spring-doc.cadn.net.cn

以下示例展示了如何同时让Spring和JUnit Jupiter将依赖项注入到placeOrderRepeatedly()测试方法中。spring-doc.cadn.net.cn

@SpringJUnitConfig(TestConfig.class)
class OrderServiceIntegrationTests {

	@RepeatedTest(10)
	void placeOrderRepeatedly(RepetitionInfo repetitionInfo,
			@Autowired OrderService orderService) {

		// use orderService from the test's ApplicationContext
		// and repetitionInfo from JUnit Jupiter
	}
}
@SpringJUnitConfig(TestConfig::class)
class OrderServiceIntegrationTests {

	@RepeatedTest(10)
	fun placeOrderRepeatedly(repetitionInfo:RepetitionInfo, @Autowired orderService:OrderService) {

		// use orderService from the test's ApplicationContext
		// and repetitionInfo from JUnit Jupiter
	}
}

请注意,从JUnit Jupiter中使用@RepeatedTest可以让测试方法获得对RepetitionInfo的访问。spring-doc.cadn.net.cn

@Nested 测试类配置

Spring TestContext Framework 自 Spring Framework 5.0 起已支持在 JUnit Jupiter 的 @Nested 测试类上使用与测试相关的注解;然而,直到 Spring Framework 5.3 之前,从包含此类的类中继承的类级别测试配置注解并未像从超类中那样被 继承spring-doc.cadn.net.cn

Spring Framework 5.3 首次支持从外部类继承测试类配置,并且这种配置默认会得到继承。要从默认的 INHERIT 模式更改为 OVERRIDE 模式,可以使用 @NestedTestConfiguration(EnclosingConfiguration.OVERRIDE) 注解单独的 @Nested 测试类。显式的 @NestedTestConfiguration 声明将适用于注解的测试类以及其任何子类和内部类。因此,您可以使用 @NestedTestConfiguration 注解一个顶层测试类,这将递归地应用于其所有内部测试类。spring-doc.cadn.net.cn

为了允许开发团队将默认值更改为 OVERRIDE - 例如,为了与 Spring Framework 5.0 到 5.2 兼容 - 可以通过 JVM 系统属性或类路径根目录下的 spring.properties 文件在全球范围内更改默认模式。有关详细信息,请参阅 "更改默认封装配置继承模式" 的说明。spring-doc.cadn.net.cn

尽管下面的“Hello World”示例非常简单,但它展示了如何在顶级类中声明常规配置,该配置被其<code>0</code>个测试类继承。在本例中,仅继承了<code>1</code>个配置类。每个嵌套测试类都提供自己的一组激活的profile,从而为每个嵌套测试类生成一个不同的<code>2</code>(有关详细信息,请参见<a t="C4">上下文缓存</a>)。查阅<a t="C5">支持的注解</a>列表,了解哪些注解可以被<code>3</code>测试类继承。spring-doc.cadn.net.cn

@SpringJUnitConfig(TestConfig.class)
class GreetingServiceTests {

	@Nested
	@ActiveProfiles("lang_en")
	class EnglishGreetings {

		@Test
		void hello(@Autowired GreetingService service) {
			assertThat(service.greetWorld()).isEqualTo("Hello World");
		}
	}

	@Nested
	@ActiveProfiles("lang_de")
	class GermanGreetings {

		@Test
		void hello(@Autowired GreetingService service) {
			assertThat(service.greetWorld()).isEqualTo("Hallo Welt");
		}
	}
}
@SpringJUnitConfig(TestConfig::class)
class GreetingServiceTests {

	@Nested
	@ActiveProfiles("lang_en")
	inner class EnglishGreetings {

		@Test
		fun hello(@Autowired service:GreetingService) {
			assertThat(service.greetWorld()).isEqualTo("Hello World")
		}
	}

	@Nested
	@ActiveProfiles("lang_de")
	inner class GermanGreetings {

		@Test
		fun hello(@Autowired service:GreetingService) {
			assertThat(service.greetWorld()).isEqualTo("Hallo Welt")
		}
	}
}

TestNG支持类

The org.springframework.test.context.testng 包提供了以下支持类用于基于 TestNG 的测试用例:spring-doc.cadn.net.cn

AbstractTestNGSpringContextTests 是一个抽象基础测试类,它将 Spring TestContext Framework 与显式的 ApplicationContext 测试支持集成在一个 TestNG 环境中。当你扩展 AbstractTestNGSpringContextTests 时,你可以访问一个 protected applicationContext 实例变量,你可以使用它来执行显式的 bean 查找或测试上下文的整体状态。spring-doc.cadn.net.cn

AbstractTransactionalTestNGSpringContextTests 是一个抽象的事务性扩展,它为 JDBC 访问添加了一些便利功能。此类期望在 ApplicationContext 中定义一个 javax.sql.DataSource bean 和一个 PlatformTransactionManager bean。当你扩展 AbstractTransactionalTestNGSpringContextTests 时,你可以访问一个 protected jdbcTemplate 实例变量,你可以使用该变量来执行 SQL 语句以查询数据库。你可以使用这些查询在运行与数据库相关的应用程序代码之前和之后确认数据库状态,并且 Spring 确保这些查询在与应用程序代码相同的事务范围内运行。AbstractTestNGSpringContextTests 需要一个 javax.sql.DataSource bean 和一个 PlatformTransactionManager bean。当你扩展 AbstractTransactionalTestNGSpringContextTests 时,你可以访问一个 protected jdbcTemplate 实例变量,用于运行 SQL 语句来查询数据库。你可以使用这些查询来确认数据库状态。Spring 确保这些查询与应用程序代码在同一事务范围内运行。当与 ORM 工具结合使用时,请确保避免 误报。如 JDBC 测试支持 中提到的那样,AbstractTransactionalTestNGSpringContextTests 还提供了便利方法,这些方法通过使用上述的 jdbcTemplate 委托到 JdbcTestUtils 中的方法。此外,AbstractTransactionalTestNGSpringContextTests 提供了一个针对配置的 DataSourceexecuteSqlScript(..) 方法。当与 ORM 工具结合使用时,请务必避免 误报。你可以在运行数据库相关应用程序代码之前和之后使用此类查询。AbstractTransactionalTestNGSpringContextTests 还提供了一些委托给 JdbcTestUtils 中的方法。AbstractTransactionalTestNGSpringContextTests 还提供了一个用于针对配置的 DataSource 运行 SQL 脚本。spring-doc.cadn.net.cn

这些类是为了方便扩展。如果你不希望你的测试类依赖于Spring特定的类层次结构,你可以通过使用@ContextConfiguration@TestExecutionListeners等,并手动为你的测试类添加一个TestContextManager来配置你自己的自定义测试类。请参阅AbstractTestNGSpringContextTests的源代码,了解如何为你的测试类添加一个TestContextManager的例子。