测试上下文框架支持类
本节描述了支持Spring TestContext Framework的各种类。
Spring JUnit 4 Runner
Spring TestContext Framework通过自定义Runner(支持JUnit 4.12或更高版本)完全集成了JUnit 4。通过使用@RunWith(SpringJUnit4ClassRunner.class)
或更短的@RunWith(SpringRunner.class)
变体对测试类进行注解,开发人员可以实现基于标准JUnit 4的单元测试和集成测试,并同时获得TestContext框架的好处,例如支持加载应用程序上下文、测试实例的依赖注入、事务性测试方法执行等。如果您想要将Spring TestContext Framework与其他Runner(例如JUnit 4的Parameterized
Runner)或第三方Runner(例如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规则
org.springframework.test.context.junit4.rules
包提供了以下JUnit 4规则(支持JUnit 4.12或更高版本):
-
SpringClassRule
-
SpringMethodRule
SpringClassRule
是一个支持Spring TestContext Framework类级特性的JUnit TestRule
,而SpringMethodRule
是一个支持实例级和方法级Spring TestContext Framework特性的JUnit MethodRule
。
与SpringRunner
相比,Spring基于规则的JUnit支持具有独立于任何org.junit.runner.Runner
实现的优势,因此可以与现有的替代Runner(例如JUnit 4的Parameterized
)或第三方Runner(例如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 Framework与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规则来配置自定义的测试类。 |
JUnit Jupiter的SpringExtension
Spring TestContext框架与JUnit Jupiter测试框架完全集成,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
// 指示JUnit Jupiter使用Spring支持扩展测试。
@ExtendWith(SpringExtension.class)
// 指示Spring从TestConfig.class加载ApplicationContext
@ContextConfiguration(classes = TestConfig.class)
class SimpleTests {
@Test
void testMethod() {
// 测试逻辑...
}
}
// 指示JUnit Jupiter使用Spring支持扩展测试。
@ExtendWith(SpringExtension::class)
// 指示Spring从TestConfig::class加载ApplicationContext
@ContextConfiguration(classes = [TestConfig::class])
class SimpleTests {
@Test
fun testMethod() {
// 测试逻辑...
}
}
由于您还可以在JUnit 5中使用注解作为元注解,Spring提供了@SpringJUnitConfig
和@SpringJUnitWebConfig
组合注解,以简化测试ApplicationContext
和JUnit Jupiter的配置。
以下示例使用@SpringJUnitConfig
来减少先前示例中使用的配置量:
-
Java
-
Kotlin
// 指示Spring向JUnit Jupiter注册SpringExtension并从TestConfig.class加载ApplicationContext
@SpringJUnitConfig(TestConfig.class)
class SimpleTests {
@Test
void testMethod() {
// 测试逻辑...
}
}
// 指示Spring向JUnit Jupiter注册SpringExtension并从TestConfig.class加载ApplicationContext
@SpringJUnitConfig(TestConfig::class)
class SimpleTests {
@Test
fun testMethod() {
// 测试逻辑...
}
}
类似地,以下示例使用@SpringJUnitWebConfig
创建WebApplicationContext
以供JUnit Jupiter使用:
-
Java
-
Kotlin
// 指示Spring向JUnit Jupiter注册SpringExtension并从TestWebConfig.class加载WebApplicationContext
@SpringJUnitWebConfig(TestWebConfig.class)
class SimpleWebTests {
@Test
void testMethod() {
// 测试逻辑...
}
}
// 指示Spring向JUnit Jupiter注册SpringExtension并从TestWebConfig::class加载WebApplicationContext
@SpringJUnitWebConfig(TestWebConfig::class)
class SimpleWebTests {
@Test
fun testMethod() {
// 测试逻辑...
}
}
有关@SpringJUnitConfig
和@SpringJUnitWebConfig
的详细信息,请参阅Spring JUnit Jupiter测试注解中的文档。
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
注解。 -
测试类上存在或元存在带有
autowireMode
属性设置为ALL
的@TestConstructor
。 -
默认的测试构造函数自动装配模式已更改为
ALL
。
有关如何使用@TestConstructor
以及如何更改全局测试构造函数自动装配模式的详细信息,请参见@TestConstructor
。
如果测试类的构造函数被认为是可自动装配的,Spring将负责解析构造函数中所有参数的参数。因此,JUnit Jupiter中注册的其他ParameterResolver 无法解析此类构造函数的参数。 |
测试类的构造函数注入不能与JUnit Jupiter的 原因是 要在与 |
在以下示例中,Spring将OrderService
bean从TestConfig.class
加载的ApplicationContext
注入到OrderServiceIntegrationTests
构造函数中。
-
Java
-
Kotlin
@SpringJUnitConfig(TestConfig.class)
class OrderServiceIntegrationTests {
private final OrderService orderService;
@Autowired
OrderServiceIntegrationTests(OrderService orderService) {
this.orderService = orderService;
}
// 使用注入的OrderService的测试
}
@SpringJUnitConfig(TestConfig::class)
class OrderServiceIntegrationTests @Autowired constructor(private val orderService: OrderService){
// 使用注入的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;
}
// 使用注入的OrderService的测试
}
@SpringJUnitConfig(TestConfig::class)
class OrderServiceIntegrationTests(val orderService:OrderService) {
// 使用注入的OrderService的测试
}
Method Injection
If a parameter in a JUnit Jupiter test method or test lifecycle callback method is of type ApplicationContext
(or a sub-type thereof) or is annotated or meta-annotated with @Autowired
, @Qualifier
, or @Value
, Spring injects the value for that specific parameter with the corresponding bean from the test’s ApplicationContext
.
In the following example, Spring injects the OrderService
from the ApplicationContext
loaded from TestConfig.class
into the deleteOrder()
test method:
-
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
}
}
Due to the robustness of the ParameterResolver
support in JUnit Jupiter, you can also have multiple dependencies injected into a single method, not only from Spring but also from JUnit Jupiter itself or other third-party extensions.
The following example shows how to have both Spring and JUnit Jupiter inject dependencies into the placeOrderRepeatedly()
test method simultaneously.
-
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
}
}
Note that the use of @RepeatedTest
from JUnit Jupiter lets the test method gain access to the RepetitionInfo
.
@Nested
测试类配置
自Spring Framework 5.0以来,Spring TestContext Framework已经支持在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
配置类被继承。每个嵌套测试类提供其自己的活动配置文件集,从而为每个嵌套测试类提供一个独立的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框架与TestNG环境中的显式ApplicationContext
测试支持集成在一起。当您扩展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
提供了一个executeSqlScript(..)
方法,用于针对配置的DataSource
运行SQL脚本。
这些类是为扩展而提供的便利。如果您不希望您的测试类与Spring特定的类层次结构绑定,您可以通过使用@ContextConfiguration 、@TestExecutionListeners 等自定义测试类,并通过手动为您的测试类配备TestContextManager 来配置自己的自定义测试类。查看AbstractTestNGSpringContextTests 的源代码,了解如何为您的测试类进行配置的示例。 |