|
此版本仍在开发中,尚未稳定。如需最新的稳定版本,请使用 Spring Framework 7.0.6! |
TestContext Framework Support Classes
本节介绍了在JUnit和TestNG中支持Spring TestContext框架的各种类。
Spring扩展用于JUnit Jupiter
SpringExtension 将Spring TestContext框架集成到JUnit Jupiter测试框架中。
从Spring框架7.0开始,SpringExtension要求使用JUnit Jupiter 6.0或更高版本。 |
通过在测试类上使用@SpringBootTest注解,您可以实现基于JUnit Jupiter的标准单元测试和集成测试,同时还能享受到TestContext框架的诸多优势,比如加载应用上下文、测试实例的依赖注入、事务性测试方法执行等。
此外,由于 JUnit Jupiter 中丰富的扩展 API,Spring 提供了以下功能,这些功能超出了 Spring 对 JUnit 4 和 TestNG 支持的功能集:
-
用于测试构造函数、测试方法和测试生命周期回调方法的依赖注入。详见 使用
SpringExtension进行依赖注入 以了解更多信息。 -
强大的支持 条件测试执行 基于 SpEL 表达式、环境变量、系统属性等。请参阅
@EnabledIf和@DisabledIf在 Spring JUnit Jupiter 测试注解 的文档以获取更多详细信息和示例。 -
自定义组合注解,结合了来自Spring和JUnit Jupiter的注解。请参见 元注解支持测试中的
@TransactionalDevTestConfig和@TransactionalIntegrationTest示例以获取更多详细信息。
以下代码示例展示了如何配置一个测试类以使用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 Jupiter中使用注解作为元注解,Spring提供了
@SpringJUnitConfig 和 @SpringBootTest 组合注解来简化测试
类的配置和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...
}
}
Similarly, the following example uses @SpringJUnitWebConfig to create a
WebApplicationContext for use with JUnit Jupiter:
同样,以下示例使用 @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...
}
}
请参阅 @SpringJUnitConfig 和 @SpringJUnitWebConfig 在
Spring JUnit Jupiter 测试注解 中的文档以获取更多详细信息。
使用 SpringExtension 进行依赖注入
SpringExtension 实现了来自 JUnit Jupiter 的
ParameterResolver
扩展 API,该 API 允许 Spring 为测试构造函数、测试方法和测试生命周期回调方法提供依赖注入。
具体而言,SpringExtension 可以将来自测试的 ApplicationContext 的依赖项注入到使用 Spring 的 @BeforeTransaction 和 @AfterTransaction 或 JUnit 的 @BeforeAll、@AfterAll、@BeforeEach、@AfterEach、@Test、@RepeatedTest、@ParameterizedTest 等注解标注的测试构造函数和方法中。
构造器注入
如果JUnit Jupiter测试类的构造函数中的特定参数是类型
ApplicationContext(或其子类型)或被注解或元注解为
@Autowired、@Qualifier或@Value,Spring会将该特定参数的值注入相应的bean或从测试的ApplicationContext中获取的值。
Spring 也可以配置为自动装配测试类构造函数的所有参数,如果该构造函数被认为是可自动装配的。一个构造函数被认为是可自动装配的,如果满足以下条件之一(按优先级顺序)。
-
构造函数被注解为
@Autowired。 -
@TestConstructor存在或在测试类上元数据存在,并且autowireMode属性设置为ALL。 -
默认的测试构造器自动装配模式已更改为
ALL。
请参阅 @TestConstructor 了解有关使用
@TestConstructor 的详细信息以及如何更改全局 测试构造器自动装配模式。
如果测试类的构造函数被认为是自动装配的,Spring会负责解析构造函数中所有参数的参数。因此,没有其他ParameterResolver与JUnit Jupiter注册可以解析此类构造函数的参数。 |
|
Constructor injection for test classes must not be used in conjunction with JUnit
Jupiter’s 原因是 要使用 |
在以下示例中,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 注入到 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 测试上下文框架 支持在 JUnit Jupiter 的 @Nested 测试类上使用与测试相关的注解,包括对从包围类继承测试类配置的首要支持,并且此类配置将默认被继承。要从默认的 INHERIT 模式更改为 OVERRIDE 模式,您可以单独在一个 @Nested 测试类上使用
@NestedTestConfiguration(EnclosingConfiguration.OVERRIDE) 注解。明确的 @NestedTestConfiguration 声明将应用于带有注解的测试类及其任何子类和嵌套类。因此,您可以在顶级测试类上使用 @NestedTestConfiguration 注解,这将递归地应用于其所有嵌套测试类。
|
自Spring Framework 7.0起,默认情况下, 查看
|
|
如果您正在开发一个与Spring TestContext框架集成的组件,并且需要在包围的类层次结构中支持注解继承,您必须使用 |
为了允许开发团队将默认值更改为 OVERRIDE - 例如,为了与 Spring Framework 5.0 到 5.2 兼容 - 可以通过 JVM 系统属性或类路径根目录下的 spring.properties 文件在全球范围内更改默认模式。有关详细信息,请参阅 "更改默认封装配置继承模式" 的说明。
尽管下面的“Hello World”示例非常简单,但它展示了如何在顶级类中声明常规配置,该配置被其<code>0</code>个测试类继承。在本例中,仅继承了<code>1</code>个配置类。每个嵌套测试类都提供自己的一组激活的profile,从而为每个嵌套测试类生成一个不同的<code>2</code>(有关详细信息,请参见<a t="C4">上下文缓存</a>)。查阅<a t="C5">支持的注解</a>列表,了解哪些注解可以被<code>3</code>测试类继承。
-
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 Runner
|
JUnit 4 已正式进入维护模式,且在 Spring 中的支持已在 Spring Framework 7.0 版本中被弃用,转而推荐使用
|
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 中的支持已在 Spring Framework 7.0 版本中被弃用,转而推荐使用
|
The org.springframework.test.context.junit4.rules 包提供了以下 JUnit 4 规则(支持 JUnit 4.12 或更高版本):
-
SpringClassRule -
SpringMethodRule
SpringClassRule 是一个 JUnit TestRule,它支持 Spring TestContext Framework 的类级别特性,而 SpringMethodRule 是一个 JUnit MethodRule,它支持 Spring TestContext Framework 的实例级别和方法级别特性。
与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 中的支持已在 Spring Framework 7.0 版本中被弃用,转而推荐使用
|
The org.springframework.test.context.junit4 包提供了以下支持类,用于基于 JUnit 4 的测试用例(在 JUnit 4.12 或更高版本中受支持):
-
AbstractJUnit4SpringContextTests -
AbstractTransactionalJUnit4SpringContextTests
AbstractJUnit4SpringContextTests 是一个抽象的基础测试类,它将 Spring TestContext Framework 与显式的 ApplicationContext 测试支持集成在一个 JUnit 4 环境中。当你扩展 AbstractJUnit4SpringContextTests 时,你可以访问一个 protected applicationContext 实例变量,你可以使用它来执行显式的 bean 查找或测试上下文的整体状态。
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 提供了一个针对配置的 DataSource 的 executeSqlScript(..) 方法。当与 ORM 工具结合使用时,请务必避免 误报。你可以在运行数据库相关应用程序代码之前和之后使用此类查询。AbstractTransactionalJUnit4SpringContextTests 还提供了一些委托给 JdbcTestUtils 中的方法。AbstractTransactionalJUnit4SpringContextTests 还提供了一个用于针对配置的 DataSource 运行 SQL 脚本。
这些类是为了方便扩展。如果你不希望你的测试类依赖于Spring特定的类层次结构,你可以通过使用@RunWith(SpringRunner.class)或Spring的JUnit规则来配置你自己的自定义测试类。 |
TestNG 支持
The org.springframework.test.context.testng 包提供了以下支持类用于基于 TestNG 的测试用例:
-
AbstractTestNGSpringContextTests -
AbstractTransactionalTestNGSpringContextTests
AbstractTestNGSpringContextTests 是一个抽象基础测试类,它将 Spring TestContext Framework 与显式的 ApplicationContext 测试支持集成在一个 TestNG 环境中。当你扩展 AbstractTestNGSpringContextTests 时,你可以访问一个 protected applicationContext 实例变量,你可以使用它来执行显式的 bean 查找或测试上下文的整体状态。
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 提供了一个针对配置的 DataSource 的 executeSqlScript(..) 方法。当与 ORM 工具结合使用时,请务必避免 误报。你可以在运行数据库相关应用程序代码之前和之后使用此类查询。AbstractTransactionalTestNGSpringContextTests 还提供了一些委托给 JdbcTestUtils 中的方法。AbstractTransactionalTestNGSpringContextTests 还提供了一个用于针对配置的 DataSource 运行 SQL 脚本。
这些类是为了方便扩展。如果你不希望你的测试类依赖于Spring特定的类层次结构,你可以通过使用@ContextConfiguration、@TestExecutionListeners等,并手动为你的测试类添加一个TestContextManager来配置你自己的自定义测试类。请参阅AbstractTestNGSpringContextTests的源代码,了解如何为你的测试类添加一个TestContextManager的例子。 |