TestContext 框架支援類別
本節描述支援 Spring TestContext 框架的各種類別。
Spring JUnit 4 執行器
Spring TestContext 框架透過自訂執行器 (在 JUnit 4.12 或更高版本上支援) 提供與 JUnit 4 的完整整合。透過使用 @RunWith(SpringJUnit4ClassRunner.class)
或較短的 @RunWith(SpringRunner.class)
變體註解測試類別,開發人員可以實作基於標準 JUnit 4 的單元和整合測試,並同時獲得 TestContext 框架的好處,例如支援載入應用程式 context、測試實例的相依性注入、交易式測試方法執行等等。如果您想將 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 規則
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
是一個抽象基礎測試類別,它在 JUnit 4 環境中將 Spring TestContext 框架與明確的 ApplicationContext
測試支援整合在一起。當您擴充 AbstractJUnit4SpringContextTests
時,您可以存取 protected
applicationContext
實例變數,您可以使用它來執行明確的 bean 查找或測試整個 context 的狀態。
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 規則來組態您自己的自訂測試類別。 |
JUnit Jupiter 的 SpringExtension
Spring TestContext 框架提供與 JUnit Jupiter 測試框架 (在 JUnit 5 中引入) 的完整整合。透過使用 @ExtendWith(SpringExtension.class)
註解測試類別,您可以實作基於標準 JUnit Jupiter 的單元和整合測試,並同時獲得 TestContext 框架的好處,例如支援載入應用程式 context、測試實例的相依性注入、交易式測試方法執行等等。
此外,由於 JUnit Jupiter 中豐富的擴充 API,Spring 提供了以下超出 Spring 對 JUnit 4 和 TestNG 支援的功能集
-
測試建構子、測試方法和測試生命週期回呼方法的相依性注入。有關更多詳細資訊,請參閱使用
SpringExtension
進行相依性注入。 -
強大的條件式測試執行支援,基於 SpEL 運算式、環境變數、系統屬性等等。有關更多詳細資訊和範例,請參閱Spring JUnit Jupiter 測試註解中
@EnabledIf
和@DisabledIf
的文件。 -
自訂組合註解,將來自 Spring 和 JUnit Jupiter 的註解組合在一起。有關更多詳細資訊,請參閱測試的 Meta-Annotation 支援中的
@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 中將註解用作 meta-annotation,因此 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
註解或 meta-annotation,則 Spring 會將該特定參數的值注入測試 ApplicationContext
中的對應 bean 或值。
如果建構子被認為是可自動裝配的,則也可以將 Spring 組態為自動裝配測試類別建構子的所有引數。如果滿足以下條件之一 (依優先順序排列),則建構子被認為是可自動裝配的。
-
建構子使用
@Autowired
註解。 -
@TestConstructor
存在或 meta-present 於測試類別上,且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
註解或 meta-annotation,則 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
測試類別上使用測試相關的註解,包括對從封閉類別繼承測試類別組態的一流支援,並且此類組態預設會被繼承。若要將預設的 INHERIT
模式變更為 OVERRIDE
模式,您可以透過 @NestedTestConfiguration(EnclosingConfiguration.OVERRIDE)
註解個別的 @Nested
測試類別。明確的 @NestedTestConfiguration
宣告將適用於註解的測試類別及其任何子類別和巢狀類別。因此,您可以使用 @NestedTestConfiguration
註解頂層測試類別,這將遞迴地適用於其所有巢狀測試類別。
如果您正在開發與 Spring TestContext 框架整合的元件,並且需要在封閉類別階層中支援註解繼承,則必須使用 |
為了讓開發團隊能夠將預設值變更為 OVERRIDE
– 例如,為了與 Spring Framework 5.0 到 5.2 相容 – 可以透過 JVM 系統屬性或類別路徑根目錄中的 spring.properties
檔案全域變更預設模式。有關詳細資訊,請參閱"變更預設封閉組態繼承模式"註解。
雖然以下 "Hello World" 範例非常簡單,但它顯示了如何在頂層類別上宣告通用組態,該組態由其 @Nested
測試類別繼承。在此特定範例中,僅繼承 TestConfig
組態類別。每個巢狀測試類別都提供自己的一組活動 profile,從而為每個巢狀測試類別產生不同的 ApplicationContext
(有關詳細資訊,請參閱Context 快取)。請參閱支援的註解列表,以查看哪些註解可以在 @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 框架與明確的 ApplicationContext
測試支援整合在一起。當您擴充 AbstractTestNGSpringContextTests
時,您可以存取 protected
applicationContext
實例變數,您可以使用它來執行明確的 bean 查找或測試整個 context 的狀態。
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 的原始碼,以了解如何檢測您的測試類別的範例。 |