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 框架的完整功能,您必須將 SpringClassRuleSpringMethodRule 結合使用。以下範例顯示在整合測試中宣告這些規則的正確方法

  • 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 的狀態。

AbstractTransactionalJUnit4SpringContextTestsAbstractJUnit4SpringContextTests 的抽象交易式擴充,它為 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 支援的功能集

以下程式碼清單顯示如何組態測試類別以結合 @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 都無法解析此類建構子的參數。

如果在使用 @DirtiesContext 在測試方法之前或之後關閉測試的 ApplicationContext 的情況下,測試類別的建構子注入不得與 JUnit Jupiter 的 @TestInstance(PER_CLASS) 支援結合使用。

原因是 @TestInstance(PER_CLASS) 指示 JUnit Jupiter 在測試方法調用之間快取測試實例。因此,測試實例將保留對最初從後續已關閉的 ApplicationContext 注入的 bean 的參考。由於在這種情況下,測試類別的建構子只會被調用一次,因此相依性注入將不會再次發生,並且後續的測試將與來自已關閉的 ApplicationContext 的 bean 互動,這可能會導致錯誤。

為了將 @DirtiesContext 與 "測試方法前" 或 "測試方法後" 模式結合 @TestInstance(PER_CLASS) 使用,必須將來自 Spring 的相依性組態為透過欄位或 setter 注入提供,以便可以在測試方法調用之間重新注入它們。

在以下範例中,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 框架整合的元件,並且需要在封閉類別階層中支援註解繼承,則必須使用 TestContextAnnotationUtils 中提供的註解搜尋公用程式,以便遵守 @NestedTestConfiguration 語意。

為了讓開發團隊能夠將預設值變更為 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 的狀態。

AbstractTransactionalTestNGSpringContextTestsAbstractTestNGSpringContextTests 的抽象交易式擴充,它為 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 的原始碼,以了解如何檢測您的測試類別的範例。