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 的原始碼,獲取如何引入您的測試類的示例。 |