TestContext 框架支持类
本节介绍支持 JUnit 和 TestNG 中 Spring TestContext 框架的各种类。
JUnit Jupiter 的 SpringExtension
Spring TestContext 框架与 JUnit Jupiter 测试框架(最初在 JUnit 5 中引入)提供了完全集成。通过使用 @ExtendWith(SpringExtension.class) 注解测试类,您可以实现标准的基于 JUnit Jupiter 的单元测试和集成测试,同时获得 TestContext 框架的优势,例如支持加载应用程序上下文、测试实例的依赖注入、事务性测试方法执行等。
此外,得益于 JUnit Jupiter 丰富的扩展 API,Spring 提供了以下超出 Spring 对 JUnit 4 和 TestNG 支持的功能集:
-
测试构造函数、测试方法和测试生命周期回调方法的依赖注入。有关详细信息,请参阅使用
SpringExtension进行依赖注入。 -
基于 SpEL 表达式、环境变量、系统属性等,对条件测试执行的强大支持。有关详细信息和示例,请参阅Spring JUnit Jupiter 测试注解中
@EnabledIf和@DisabledIf的文档。 -
结合 Spring 和 JUnit Jupiter 注解的自定义组合注解。有关详细信息,请参阅测试的元注解支持中的
@TransactionalDevTestConfig和@TransactionalIntegrationTest示例。
以下代码清单显示了如何配置测试类以与 @ContextConfiguration 结合使用 SpringExtension:
-
Java
-
Kotlin
// 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...
}
}
由于您还可以在 JUnit Jupiter 中将注解用作元注解,因此 Spring 提供了 @SpringJUnitConfig 和 @SpringJUnitWebConfig 组合注解,以简化测试 ApplicationContext 和 JUnit Jupiter 的配置。
以下示例使用 @SpringJUnitConfig 来减少上一个示例中使用的配置量:
-
Java
-
Kotlin
// 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...
}
}
类似地,以下示例使用 @SpringJUnitWebConfig 为 JUnit Jupiter 创建 WebApplicationContext:
-
Java
-
Kotlin
// 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...
}
}
有关详细信息,请参阅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 或值注入该特定参数的值。
如果构造函数被认为是可自动装配的,Spring 还可以配置为自动装配测试类构造函数的所有参数。如果满足以下条件之一(按优先级顺序),则构造函数被认为是可自动装配的。
-
构造函数使用
@Autowired注解。 -
@TestConstructor存在或元存在于测试类上,其autowireMode属性设置为ALL。 -
默认的测试构造函数自动装配模式已更改为
ALL。
有关 @TestConstructor 的使用以及如何更改全局测试构造函数自动装配模式的详细信息,请参阅@TestConstructor。
如果测试类的构造函数被认为是可自动装配的,Spring 将负责解析构造函数中所有参数的参数。因此,注册到 JUnit Jupiter 的其他 ParameterResolver 不能为此类构造函数解析参数。 |
|
如果使用 原因是 要将 |
在以下示例中,Spring 将从 TestConfig.class 加载的 ApplicationContext 中的 OrderService bean 注入到 OrderServiceIntegrationTests 构造函数中。
-
Java
-
Kotlin
@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.test.constructor.autowire.mode 属性设置为 all(请参阅@TestConstructor),我们可以在上一个示例中省略构造函数上的 @Autowired 声明,结果如下。
-
Java
-
Kotlin
@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 将从 TestConfig.class 加载的 ApplicationContext 中的 OrderService 注入到 deleteOrder() 测试方法中:
-
Java
-
Kotlin
@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 和 JUnit Jupiter 的依赖项注入到 placeOrderRepeatedly() 测试方法中。
-
Java
-
Kotlin
@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。
@Nested 测试类配置
Spring TestContext 框架支持在 JUnit Jupiter 的 @Nested 测试类上使用与测试相关的注解,包括对从封闭类继承测试类配置的一流支持,并且此类配置将默认继承。要从默认的 INHERIT 模式更改为 OVERRIDE 模式,您可以为单个 @Nested 测试类添加 @NestedTestConfiguration(EnclosingConfiguration.OVERRIDE) 注解。显式的 @NestedTestConfiguration 声明将应用于带注解的测试类及其任何子类和嵌套类。因此,您可以为顶级测试类添加 @NestedTestConfiguration 注解,它将递归应用于其所有嵌套测试类。
|
如果您正在开发与 Spring TestContext 框架集成的组件,并且需要支持封闭类层次结构中的注解继承,则必须使用 |
为了允许开发团队将默认值更改为 OVERRIDE——例如,为了与 Spring Framework 5.0 到 5.2 兼容——可以通过 JVM 系统属性或 classpath 根目录下的 spring.properties 文件全局更改默认模式。有关详细信息,请参阅“更改默认封闭配置继承模式”注释。
尽管以下“Hello World”示例非常简单,但它展示了如何在顶级类上声明由其 @Nested 测试类继承的通用配置。在此特定示例中,只继承了 TestConfig 配置类。每个嵌套测试类提供其自己的一组活动配置文件,从而为每个嵌套测试类提供一个不同的 ApplicationContext(有关详细信息,请参阅上下文缓存)。查阅支持的注解列表,以查看哪些注解可以在 @Nested 测试类中继承。
-
Java
-
Kotlin
@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")
}
}
}
JUnit 4 支持
Spring JUnit 4 运行器
|
JUnit 4 正式处于维护模式,并且自 Spring Framework 7.0 起,Spring 中的 JUnit 4 支持已被弃用,转而支持 |
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 Runner 运行的最低要求:
-
Java
-
Kotlin
@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 配置 ApplicationContext。
Spring JUnit 4 规则
|
JUnit 4 正式处于维护模式,并且自 Spring Framework 7.0 起,Spring 中的 JUnit 4 支持已被弃用,转而支持 |
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 框架的完整功能,您必须将 SpringClassRule 与 SpringMethodRule 结合使用。以下示例显示了在集成测试中声明这些规则的正确方法:
-
Java
-
Kotlin
// 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 基类
|
JUnit 4 正式处于维护模式,并且自 Spring Framework 7.0 起,Spring 中的 JUnit 4 支持已被弃用,转而支持 |
org.springframework.test.context.junit4 包为基于 JUnit 4 的测试用例提供了以下支持类(支持 JUnit 4.12 或更高版本):
-
AbstractJUnit4SpringContextTests -
AbstractTransactionalJUnit4SpringContextTests
AbstractJUnit4SpringContextTests 是一个抽象基类测试类,它将 Spring TestContext 框架与 JUnit 4 环境中的显式 ApplicationContext 测试支持集成。当您扩展 AbstractJUnit4SpringContextTests 时,您可以访问一个 protected 的 applicationContext 实例变量,您可以使用它来执行显式 bean 查找或测试整个上下文的状态。
AbstractTransactionalJUnit4SpringContextTests 是 AbstractJUnit4SpringContextTests 的一个抽象事务扩展,它增加了一些方便的 JDBC 访问功能。此类期望在 ApplicationContext 中定义 javax.sql.DataSource bean 和 PlatformTransactionManager bean。当您扩展 AbstractTransactionalJUnit4SpringContextTests 时,您可以访问一个 protected 的 jdbcTemplate 实例变量,您可以使用它来运行 SQL 语句来查询数据库。您可以使用此类查询来确认在运行数据库相关应用程序代码之前和之后的数据库状态,并且 Spring 确保此类查询在与应用程序代码相同的事务范围内运行。与 ORM 工具结合使用时,请务必避免假阳性。如JDBC 测试支持中所述,AbstractTransactionalJUnit4SpringContextTests 还提供了委托给 JdbcTestUtils 中方法的便利方法,通过使用上述 jdbcTemplate。此外,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 时,您可以访问一个 protected 的 applicationContext 实例变量,您可以使用它来执行显式 bean 查找或测试整个上下文的状态。
AbstractTransactionalTestNGSpringContextTests 是 AbstractTestNGSpringContextTests 的一个抽象事务扩展,它增加了一些方便的 JDBC 访问功能。此类期望在 ApplicationContext 中定义 javax.sql.DataSource bean 和 PlatformTransactionManager bean。当您扩展 AbstractTransactionalTestNGSpringContextTests 时,您可以访问一个 protected 的 jdbcTemplate 实例变量,您可以使用它来运行 SQL 语句来查询数据库。您可以使用此类查询来确认在运行数据库相关应用程序代码之前和之后的数据库状态,并且 Spring 确保此类查询在与应用程序代码相同的事务范围内运行。与 ORM 工具结合使用时,请务必避免假阳性。如JDBC 测试支持中所述,AbstractTransactionalTestNGSpringContextTests 还提供了委托给 JdbcTestUtils 中方法的便利方法,通过使用上述 jdbcTemplate。此外,AbstractTransactionalTestNGSpringContextTests 提供了 executeSqlScript(..) 方法,用于针对配置的 DataSource 运行 SQL 脚本。
这些类是为了方便扩展。如果您不想让您的测试类绑定到 Spring 特定的类层次结构,您可以使用 @ContextConfiguration、@TestExecutionListeners 等配置您自己的自定义测试类,并通过 TestContextManager 手动检测您的测试类。有关如何检测测试类的示例,请参阅 AbstractTestNGSpringContextTests 的源代码。 |