TestContext 框架支持类
本节描述了支持 Spring TestContext 框架的各种类。
Spring JUnit 4 Runner
Spring TestContext 框架通过自定义 runner (支持 JUnit 4.12 或更高版本) 与 JUnit 4 完全集成。通过使用 @RunWith(SpringJUnit4ClassRunner.class)
或更短的 @RunWith(SpringRunner.class)
变体注解测试类,开发人员可以实现标准的基于 JUnit 4 的单元测试和集成测试,同时享受 TestContext 框架的优势,例如支持加载应用上下文、测试实例的依赖注入、事务性测试方法执行等。如果你想将 Spring TestContext 框架与另一个 runner (例如 JUnit 4 的 Parameterized
runner) 或第三方 runner (例如 MockitoJUnitRunner
) 一起使用,你可以选择使用Spring 对 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
配置了一个空列表,以禁用默认的监听器,否则它们需要通过 @ContextConfiguration
配置一个 ApplicationContext
。
Spring JUnit 4 Rules
org.springframework.test.context.junit4.rules
包提供了以下 JUnit 4 rules (支持 JUnit 4.12 或更高版本)
-
SpringClassRule
-
SpringMethodRule
SpringClassRule
是一个支持 Spring TestContext 框架类级别特性的 JUnit TestRule
,而 SpringMethodRule
是一个支持 Spring TestContext 框架实例级别和方法级别特性的 JUnit MethodRule
。
与 SpringRunner
不同,Spring 基于 rule 的 JUnit 支持的优势在于它独立于任何 org.junit.runner.Runner
实现,因此可以与现有的替代 runner (例如 JUnit 4 的 Parameterized
) 或第三方 runner (例如 MockitoJUnitRunner
) 结合使用。
为了支持 TestContext 框架的全部功能,你必须将 SpringClassRule
与 SpringMethodRule
结合使用。以下示例显示了在集成测试中声明这些 rules 的正确方法
-
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
是一个抽象基测试类,它在 JUnit 4 环境中集成了 Spring TestContext 框架和显式 ApplicationContext
测试支持。当你扩展 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
提供了一个 executeSqlScript(..)
方法,用于针对配置的 DataSource
运行 SQL 脚本。
这些类是为了扩展方便而提供的。如果你不想让你的测试类绑定到 Spring 特定的类层次结构,你可以使用 @RunWith(SpringRunner.class) 或Spring 的 JUnit rules 来配置你自己的自定义测试类。 |
用于 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 5 中将注解用作元注解,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 测试注解中关于 @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
测试类上使用测试相关注解,包括对从 enclosing 类继承测试类配置的一流支持,并且这种配置将默认继承。要将默认的 INHERIT
模式更改为 OVERRIDE
模式,你可以在单个 @Nested
测试类上使用 @NestedTestConfiguration(EnclosingConfiguration.OVERRIDE)
注解。显式的 @NestedTestConfiguration
声明将应用于被注解的测试类及其任何子类和嵌套类。因此,你可以在顶层测试类上使用 @NestedTestConfiguration
注解,它将递归地应用于其所有嵌套测试类。
如果您正在开发与 Spring TestContext Framework 集成并需要在封闭类层次结构中支持注解继承的组件,则必须使用 |
为了允许开发团队将默认设置更改为 OVERRIDE
(例如,为了与 Spring Framework 5.0 至 5.2 兼容),可以通过 JVM 系统属性或类路径根目录下的 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")
}
}
}
TestNG 支持类
org.springframework.test.context.testng
包为基于 TestNG 的测试用例提供了以下支持类
-
AbstractTestNGSpringContextTests
-
AbstractTransactionalTestNGSpringContextTests
AbstractTestNGSpringContextTests
是一个抽象基础测试类,它在 TestNG 环境中将 Spring TestContext Framework 与显式的 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 的源代码,获取如何引入您的测试类的示例。 |