跳到主要内容
版本:7.0.3

TestContext框架支持类

Hunyuan 7b 中英对照 TestContext Framework Support Classes

本节描述了JUnit和TestNG中支持Spring TestContext框架的各种类。

SpringExtension for JUnit Jupiter

SpringExtension 将 Spring TestContext 框架集成到了 JUnit Jupiter 测试框架中。

备注

从 Spring Framework 7.0 开始,SpringExtension 需要 JUnit Jupiter 6.0 或更高版本。

通过使用@ExtendWith(SpringExtension.class)注释测试类,你可以实现基于JUnit Jupiter的标准单元测试和集成测试,同时还能享受到TestContext框架带来的好处,例如支持加载应用程序上下文、对测试实例进行依赖注入、事务性测试方法执行等功能。

此外,得益于JUnit Jupiter中丰富的扩展API,Spring提供了以下超出Spring对JUnit 4和TestNG所支持功能集的额外特性:

  • 为测试构造函数、测试方法和测试生命周期回调方法提供依赖注入功能。有关更多详细信息,请参阅使用SpringExtension进行依赖注入

  • 强大地支持基于SpEL表达式、环境变量、系统属性等的条件化测试执行。有关@EnabledIf@DisabledIf的更多详细信息和示例,请参阅Spring JUnit Jupiter测试注解中的文档。

  • 提供自定义组合注解,这些注解结合了Spring和JUnit Jupiter的注解功能。有关更多详细信息,请参阅元注解支持用于测试中的@TransactionalDevTestConfig@TransactionalIntegrationTest示例。

以下代码示例展示了如何配置一个测试类,以便与@ContextConfiguration一起使用SpringExtension

// 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...
}
}

由于你也可以在 JUnit Jupiter 中将注释用作元注释(meta-annotations),Spring 提供了 @SpringJUnitConfig@SpringJUnitWebConfig 这两种组合注释,以简化测试 ApplicationContext 以及 JUnit Jupiter 的配置。

以下示例使用了@SpringJUnitConfig来减少上一个示例中使用的配置量:

// 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...
}
}

同样,以下示例使用@SpringJUnitWebConfig来创建一个WebApplicationContext,以便与JUnit Jupiter一起使用:

// 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...
}
}

有关更多详细信息,请参阅Spring JUnit Jupiter 测试注解中关于@SpringJUnitConfig@SpringJUnitWebConfig的文档。

使用 SpringExtension 进行依赖注入

SpringExtension 实现了 JUnit Jupiter 的 ParameterResolver 扩展 API,这使得 Spring 能够为测试构造函数、测试方法以及测试生命周期回调方法提供依赖注入功能。

具体来说,SpringExtension可以将测试的ApplicationContext中的依赖注入到被Spring的@BeforeTransaction@AfterTransaction或JUnit的@BeforeAll@AfterAll@BeforeEach@AfterEach@Test@RepeatedTest@ParameterizedTest等注解标注的测试构造函数和方法中。

构造函数注入

如果JUnit Jupiter测试类构造函数中的某个特定参数类型为ApplicationContext(或其子类型),或者被@Autowired@Qualifier@Value注解或元注解,则Spring会从测试的ApplicationContext中注入相应的bean或值作为该参数的值。

如果一个测试类构造函数被视为“可自动注入的”(autowirable),那么Spring也可以配置为自动注入该构造函数的所有参数。当满足以下条件之一时(按优先级顺序),则认为该构造函数是可自动注入的。

  • 构造函数被注解为 @Autowired

  • 测试类上存在 @TestConstructor 注解,或者该注解以元注解(meta-annotation)的形式存在,并且其 autowireMode 属性被设置为 ALL

  • 默认的“测试构造函数自动注入模式”(test constructor autowire mode)已被更改为 ALL

有关@TestConstructor的用法以及如何更改全局测试构造函数自动装配模式的详细信息,请参阅@TestConstructor

注意

如果一个测试类的构造函数被认为是可自动注入的(autowirable),那么Spring将负责为该构造函数中的所有参数解析参数值。因此,任何其他在JUnit Jupiter中注册的ParameterResolver都无法为这样的构造函数解析参数。

注意

如果在测试方法之前或之后使用@DirtiesContext来关闭测试的ApplicationContext,则不能将构造函数注入(constructor injection)用于测试类,并同时使用JUnit Jupiter的@TestInstance(PER_CLASS)支持。

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

要结合@TestInstance(PER_CLASS)在“测试方法之前”或“测试方法之后”的模式下使用@DirtiesContext,必须将Spring的依赖配置为通过字段注入或setter注入提供,以便在测试方法调用之间能够重新进行注入。

在以下示例中,Spring 从通过 TestConfig.class 加载的 ApplicationContext 中注入 OrderService bean 到 OrderServiceIntegrationTests 的构造函数中。

@SpringJUnitConfig(TestConfig.class)
class OrderServiceIntegrationTests {

private final OrderService orderService;

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

// tests that use the injected OrderService
}

请注意,此功能允许测试依赖项为final类型,因此是不可变的。

如果 spring.test.constructor-autowire.mode 的值为 all(参见 @TestConstructor),那么在之前的示例中,我们可以省略构造函数上的 @Autowired 声明,从而得到以下结果。

@SpringJUnitConfig(TestConfig.class)
class OrderServiceIntegrationTests {

private final OrderService orderService;

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

// tests that use the injected OrderService
}

方法注入

如果JUnit Jupiter测试方法或测试生命周期回调方法中的参数类型为ApplicationContext(或其子类型),或者被@Autowired@Qualifier@Value注解或元注解,则Spring会从测试的ApplicationContext中注入相应的bean值作为该参数的值。

在以下示例中,Spring从通过TestConfig.class加载的ApplicationContext中注入OrderServicedeleteOrder()测试方法中:

@SpringJUnitConfig(TestConfig.class)
class OrderServiceIntegrationTests {

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

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

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

@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
}
}

请注意,使用JUnit Jupiter中的@RepeatedTest可以让测试方法访问RepetitionInfo对象。

@Nested 测试类配置

Spring TestContext Framework 支持在 JUnit Jupiter 中的 @Nested 测试类上使用与测试相关的注解,包括对从外层类继承测试类配置的一级支持,而且这种配置会默认被继承。要将默认的 INHERIT 模式更改为 OVERRIDE 模式,你可以使用 @NestedTestConfiguration(EnclosingConfiguration.OVERRIDE) 注解来标注单个 @Nested 测试类。显式的 @NestedTestConfiguration 声明将适用于被标注的测试类及其所有子类和嵌套类。因此,你可以在顶级测试类上使用 @NestedTestConfiguration 注解,该注解将会递归地应用于其所有的嵌套测试类。

提示

如果您正在开发一个与Spring TestContext框架集成的组件,并且需要支持嵌套类层次结构中的注解继承,那么您必须使用TestContextAnnotationUtils中提供的注解搜索工具,以便遵循@NestedTestConfiguration的语义。

为了允许开发团队将默认模式更改为OVERRIDE——例如,为了与Spring Framework 5.0到5.2兼容——可以通过JVM系统属性或在类路径根目录下的spring.properties文件来全局更改默认模式。请参阅“更改默认的封装配置继承模式”说明以获取详细信息。

尽管以下的“Hello World”示例非常简单,但它展示了如何在顶级类上声明通用配置,这些配置会被其@Nested测试类继承。在这个特定的示例中,只有TestConfig配置类被继承。每个嵌套的测试类都提供自己的一组活动配置文件(active profiles),因此每个嵌套的测试类都会有一个独立的ApplicationContext(详情请参见上下文缓存)。请查阅支持的注解列表,以了解哪些注解可以在@Nested测试类中被继承。

@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");
}
}
}

JUnit 4 支持

Spring JUnit 4 运行器

注意

JUnit 4 已正式进入维护模式,自 Spring Framework 7.0 起,Spring 中对 JUnit 4 的支持已被弃用,转而支持 SpringExtension 和 JUnit Jupiter。

Spring TestContext框架通过一个自定义运行器与JUnit 4实现了完全集成(支持JUnit 4.12或更高版本)。通过使用@RunWith(SpringJUnit4ClassRunner.class)或更简洁的@RunWith(SpringRunner.class)注解来标记测试类,开发者可以执行基于JUnit 4的标准单元测试和集成测试,同时还能享受到TestContext框架带来的诸多好处,例如加载应用程序上下文的支持、测试实例的依赖注入、事务性测试方法执行等功能。如果想要使用其他运行器(如JUnit 4的Parameterized运行器)或第三方运行器(如MockitoJUnitRunner),也可以选择利用Spring对JUnit规则的支持来实现。

以下代码示例展示了配置测试类以使用自定义的Spring Runner运行所需的最基本要求:

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

@Test
public void testMethod() {
// test logic...
}
}

在前面的例子中,@TestExecutionListeners 被配置为一个空列表,以此来禁用默认的监听器。否则,就需要通过 @ContextConfiguration 来配置一个 ApplicationContext

Spring JUnit 4 规则

注意

JUnit 4现已正式进入维护模式,自Spring Framework 7.0起,Spring中对JUnit 4的支持已被弃用,取而代之的是SpringExtension和JUnit Jupiter。

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

  • SpringClassRule
  • SpringMethodRule

SpringClassRule 是一个 JUnit TestRule,它支持 Spring TestContext 框架的类级特性;而 SpringMethodRule 则是一个 JUnit MethodRule,它支持 Spring TestContext 框架的实例级和方法级特性。

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

为了支持TestContext框架的全部功能,你必须将SpringClassRuleSpringMethodRule结合使用。以下示例展示了在集成测试中正确声明这些规则的方法:

// 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...
}
}

JUnit 4基础类

注意

JUnit 4 已正式进入维护模式,从 Spring Framework 7.0 开始,Spring 对 JUnit 4 的支持已被弃用,转而支持 SpringExtension 和 JUnit Jupiter。

org.springframework.test.context.junit4 包为基于 JUnit 4 的测试用例提供了以下支持类(在 JUnit 4.12 或更高版本中得到支持):

  • AbstractJUnit4SpringContextTests

  • AbstractTransactionalJUnit4SpringContextTests

AbstractJUnit4SpringContextTests 是一个抽象的基测试类,它将 Spring TestContext 框架与 JUnit 4 环境中的显式 ApplicationContext 测试支持集成在一起。当你继承 AbstractJUnit4SpringContextTests 时,你可以访问一个受保护的 applicationContext 实例变量,可以使用该变量来执行显式的bean查找,或者测试整个上下文的状态。

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

提示

这些类为扩展提供了便利。如果你不希望你的测试类与Spring特定的类层次结构相关联,你可以使用@RunWith(SpringRunner.class)Spring的JUnit规则来配置自己的自定义测试类。

TestNG支持

org.springframework.test.context.testng 包为基于 TestNG 的测试用例提供了以下支持类:

  • AbstractTestNGSpringContextTests

  • AbstractTransactionalTestNGSpringContextTests

AbstractTestNGSpringContextTests 是一个抽象的基测试类,它将 Spring TestContext 框架与在 TestNG 环境中的显式 ApplicationContext 测试支持集成在一起。当你继承 AbstractTestNGSpringContextTests 时,你可以访问一个受保护的(protectedapplicationContext 实例变量,该变量可以用来执行显式的bean查找操作,或者用来测试整个上下文的状态。

AbstractTransactionalTestNGSpringContextTestsAbstractTestNGSpringContextTests 的一个抽象事务扩展类,它为 JDBC 访问增加了一些便捷功能。该类要求在 ApplicationContext 中定义一个 javax.sql.DataSource bean 和一个 PlatformTransactionManager bean。当你继承 AbstractTransactionalTestNGSpringContextTests 时,你可以访问一个受保护的 jdbcTemplate 实例变量,该变量可用于运行 SQL 语句来查询数据库。你可以利用这些查询在运行与数据库相关的应用程序代码之前和之后确认数据库状态,而 Spring 会确保这些查询在与应用程序代码相同的交易范围内执行。当与 ORM 工具一起使用时,请务必避免 误报。如 JDBC 测试支持 中所述,AbstractTransactionalTestNGSpringContextTests 还提供了便捷方法,这些方法通过使用上述的 jdbcTemplate 来调用 JdbcTestUtils 中的方法。此外,AbstractTransactionalTestNGSpringContextTests 还提供了一个 executeSqlScript(..) 方法,用于针对配置的 DataSource 运行 SQL 脚本。

提示

这些类为扩展提供了便利。如果你不希望你的测试类与Spring特定的类层次结构绑定,你可以使用@ContextConfiguration@TestExecutionListeners等注解来配置自己的自定义测试类,并手动为测试类添加TestContextManager。可以参考AbstractTestNGSpringContextTests的源代码,了解如何为测试类添加这些功能的示例。