|
对于最新稳定版本,请使用 Spring Framework 7.0.6! |
测试上下文框架支持类
本节介绍支持 Spring TestContext 框架的各种类。
Spring JUnit 4 运行器
Spring TestContext 框架通过自定义运行器(支持 JUnit 4.12 或更高版本)与 JUnit 4 实现了完全集成。通过在测试类上使用 @RunWith(SpringJUnit4ClassRunner.class) 注解,或者更简短的 @RunWith(SpringRunner.class) 变体,开发者可以编写基于标准 JUnit 4 的单元测试和集成测试,同时还能享受 TestContext 框架带来的诸多优势,例如加载应用上下文、对测试实例进行依赖注入、事务化的测试方法执行等。如果你希望在使用其他运行器(例如 JUnit 4 的 Parameterized 运行器)或第三方运行器(例如 MockitoJUnitRunner)的同时使用 Spring TestContext 框架,也可以选择使用 Spring 对 JUnit 规则(JUnit Rules)的支持。
以下代码清单展示了配置测试类以使用自定义 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 被配置为一个空列表,以禁用默认监听器;否则,默认监听器将要求通过 ApplicationContext 配置一个 @ContextConfiguration。
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 支持类
org.springframework.test.context.junit4 包为基于 JUnit 4 的测试用例提供了以下支持类(支持 JUnit 4.12 或更高版本):
-
AbstractJUnit4SpringContextTests -
AbstractTransactionalJUnit4SpringContextTests
AbstractJUnit4SpringContextTests 是一个抽象基测试类,它将 Spring TestContext 框架与显式的 ApplicationContext 测试支持集成到 JUnit 4 环境中。当你继承 AbstractJUnit4SpringContextTests 时,可以访问一个受保护(protected)的 applicationContext 实例变量,用于执行显式的 Bean 查找,或测试整个上下文的状态。
AbstractTransactionalJUnit4SpringContextTests 是 AbstractJUnit4SpringContextTests 的一个抽象事务扩展类,为 JDBC 访问增加了一些便捷功能。此类期望在ApplicationContext中定义一个javax.sql.DataSource bean 和一个PlatformTransactionManager bean。当您
扩展 AbstractTransactionalJUnit4SpringContextTests,您可以访问一个 protected
jdbcTemplate 实例变量,可以使用它来运行 SQL 语句以查询数据库。您可以使用此类查询来验证数据库状态,无论是在执行与数据库相关的应用程序代码之前还是之后,Spring 都会确保这些查询在与应用程序代码相同的事务范围内运行。当与 ORM 工具结合使用时,请务必避免误报。如在JDBC 测试支持中所述,AbstractTransactionalJUnit4SpringContextTests还提供了便利方法,这些方法通过使用前述的jdbcTemplate来委托给JdbcTestUtils中的方法。此外,AbstractTransactionalJUnit4SpringContextTests 提供了一个用于执行 SQL 脚本的 executeSqlScript(..) 方法,针对配置好的 DataSource。
这些类是为了方便扩展而提供的。如果你不希望你的测试类绑定到 Spring 特定的类层次结构,可以通过使用 @RunWith(SpringRunner.class) 或 Spring 的 JUnit 规则 来配置你自己的自定义测试类。 |
用于 JUnit Jupiter 的 Spring 扩展
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 测试注解文档中关于
xref page和../annotations/integration-junit-jupiter.html的说明。 -
自定义组合注解,用于结合 Spring 和 JUnit Jupiter 的注解。更多详情,请参见测试的元注解支持中的
xref page和../annotations/integration-meta.html示例。
以下代码清单展示了如何配置一个测试类,以结合使用 SpringExtension 和 @ContextConfiguration:
-
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 5 中将注解用作元注解(meta-annotations),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 创建一个
WebApplicationContext,以便与 JUnit Jupiter 配合使用:
-
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 测试注解文档中关于xref page和../annotations/integration-junit-jupiter.html的部分。
使用依赖注入的SpringExtension
SpringExtension 实现了来自 JUnit Jupiter 的
ParameterResolver
扩展 API,这使得 Spring 能够为测试构造函数、测试方法以及测试生命周期回调方法提供依赖注入。
具体来说,SpringExtension 可以从测试的ApplicationContext中注入依赖到使用@BeforeAll、@AfterAll、@BeforeEach、@AfterEach、@Test、@RepeatedTest、@ParameterizedTest等注解修饰的测试构造函数和方法中。
构造函数注入
如果 JUnit Jupiter 测试类构造函数中的某个特定参数类型为 ApplicationContext(或其子类型),或者该参数被 @Autowired、@Qualifier 或 @Value 注解(或元注解)所标注,Spring 将从测试的 ApplicationContext 中注入相应的 Bean 或值到该参数。
如果测试类的构造函数被认为是可自动装配的(autowirable),Spring 还可以配置为自动装配该构造函数的所有参数。当满足以下任一条件时(按优先级顺序),该构造函数就被视为可自动装配的。
-
构造函数使用
@Autowired注解进行标注。 -
@TestConstructor注解存在于测试类上或通过元注解存在,并且其autowireMode属性设置为ALL。 -
默认的测试构造函数自动装配模式已更改为
ALL。
有关 @TestConstructor 的使用以及如何更改全局测试构造函数自动装配模式的详细信息,请参阅 @TestConstructor。
如果测试类的构造函数被视为可自动装配(autowirable),Spring 将负责解析该构造函数中所有参数的值。
因此,JUnit Jupiter 中注册的其他任何 ParameterResolver 都无法为此类构造函数解析参数。 |
|
如果使用 原因是 要将 |
在以下示例中,Spring 将从通过 OrderService 加载的 ApplicationContext 中注入 TestConfig.class 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 将从 OrderService 加载的 ApplicationContext 中的 TestConfig.class 注入到 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 Framework 5.0 起,Spring TestContext 框架已支持在 JUnit Jupiter 的 @Nested 测试类上使用与测试相关的注解;然而,直到 Spring Framework 5.3 为止,类级别的测试配置注解还不能像从父类继承那样从外围类中继承。
Spring Framework 5.3 引入了对从外部类继承测试类配置的一流支持,并且此类配置默认会被继承。若要将默认的 INHERIT 模式更改为 OVERRIDE 模式,您可以在单个 @Nested 测试类上添加注解 @NestedTestConfiguration(EnclosingConfiguration.OVERRIDE)。显式声明的 @NestedTestConfiguration 将应用于被注解的测试类及其所有子类和嵌套类。因此,您可以在顶层测试类上添加 @NestedTestConfiguration 注解,该注解将递归地应用于其所有嵌套测试类。
为了允许开发团队将默认值更改为 OVERRIDE——例如,
以兼容 Spring Framework 5.0 至 5.2 版本——可以通过 JVM 系统属性或位于类路径根目录下的 spring.properties 文件全局更改默认模式。详情请参见“更改默认的封闭配置继承模式”说明。
尽管下面的“Hello World”示例非常简单,但它展示了如何在顶层类上声明通用配置,并由其 @Nested 测试类继承。在本例中,仅继承了 TestConfig 配置类。每个嵌套测试类都提供自己的一组激活的配置文件(active profiles),从而为每个嵌套测试类生成一个独立的 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")
}
}
}
TestNG 支持类
org.springframework.test.context.testng 包为基于 TestNG 的测试用例提供了以下支持类:
-
AbstractTestNGSpringContextTests -
AbstractTransactionalTestNGSpringContextTests
AbstractTestNGSpringContextTests 是一个抽象基测试类,它将 Spring TestContext 框架与显式的 ApplicationContext 测试支持集成到 TestNG 环境中。当你继承 AbstractTestNGSpringContextTests 时,可以访问一个受保护(protected)的 applicationContext 实例变量,用于执行显式的 Bean 查找,或测试整个上下文的状态。
AbstractTransactionalTestNGSpringContextTests 是 AbstractTestNGSpringContextTests 的一个抽象事务扩展类,为 JDBC 访问增加了一些便捷功能。此类期望在ApplicationContext中定义一个javax.sql.DataSource bean 和一个PlatformTransactionManager bean。当您
扩展 AbstractTransactionalTestNGSpringContextTests,您可以访问一个 protected
jdbcTemplate 实例变量,可以使用它来运行 SQL 语句以查询数据库。您可以使用此类查询来验证数据库状态,无论是在执行与数据库相关的应用程序代码之前还是之后,Spring 都会确保这些查询在与应用程序代码相同的事务范围内运行。当与 ORM 工具结合使用时,请务必避免误报。如在JDBC 测试支持中所述,AbstractTransactionalTestNGSpringContextTests还提供了便利方法,这些方法通过使用前述的jdbcTemplate来委托给JdbcTestUtils中的方法。此外,AbstractTransactionalTestNGSpringContextTests 提供了一个用于执行 SQL 脚本的 executeSqlScript(..) 方法,针对配置好的 DataSource。
这些类是为了方便扩展而提供的。如果你不希望你的测试类绑定到 Spring 特定的类层次结构,你可以通过使用 @ContextConfiguration、@TestExecutionListeners 等注解,并手动在你的测试类中使用 TestContextManager 进行装配,来配置你自己的自定义测试类。有关如何装配测试类的示例,请参见 AbstractTestNGSpringContextTests 的源代码。 |