TestContext 框架支援類

本節介紹支援 JUnit 和 TestNG 中 Spring TestContext 框架的各種類。

JUnit Jupiter 的 SpringExtension

Spring TestContext 框架與 JUnit Jupiter 測試框架(最初在 JUnit 5 中引入)提供了完全整合。透過使用 @ExtendWith(SpringExtension.class) 註解測試類,您可以實現標準的基於 JUnit Jupiter 的單元測試和整合測試,同時獲得 TestContext 框架的優勢,例如支援載入應用程式上下文、測試例項的依賴注入、事務性測試方法執行等。

此外,得益於 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 Jupiter 中將註解用作元註解,因此 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 為 JUnit Jupiter 建立 WebApplicationContext

  • 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 不能為此類建構函式解析引數。

如果使用 @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 進行註解或元註解,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 模式,您可以為單個 @Nested 測試類新增 @NestedTestConfiguration(EnclosingConfiguration.OVERRIDE) 註解。顯式的 @NestedTestConfiguration 宣告將應用於帶註解的測試類及其任何子類和巢狀類。因此,您可以為頂級測試類新增 @NestedTestConfiguration 註解,它將遞迴應用於其所有巢狀測試類。

如果您正在開發與 Spring TestContext 框架整合的元件,並且需要支援封閉類層次結構中的註解繼承,則必須使用 TestContextAnnotationUtils 中提供的註解搜尋實用程式,以遵循 @NestedTestConfiguration 語義。

為了允許開發團隊將預設值更改為 OVERRIDE——例如,為了與 Spring Framework 5.0 到 5.2 相容——可以透過 JVM 系統屬性或 classpath 根目錄下的 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")
		}
	}
}

JUnit 4 支援

Spring JUnit 4 執行器

JUnit 4 正式處於維護模式,並且自 Spring Framework 7.0 起,Spring 中的 JUnit 4 支援已被棄用,轉而支援SpringExtension 和 JUnit Jupiter。

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 Framework 7.0 起,Spring 中的 JUnit 4 支援已被棄用,轉而支援SpringExtension 和 JUnit Jupiter。

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 基類

JUnit 4 正式處於維護模式,並且自 Spring Framework 7.0 起,Spring 中的 JUnit 4 支援已被棄用,轉而支援SpringExtension 和 JUnit Jupiter。

org.springframework.test.context.junit4 包為基於 JUnit 4 的測試用例提供了以下支援類(支援 JUnit 4.12 或更高版本):

  • AbstractJUnit4SpringContextTests

  • AbstractTransactionalJUnit4SpringContextTests

AbstractJUnit4SpringContextTests 是一個抽象基類測試類,它將 Spring TestContext 框架與 JUnit 4 環境中的顯式 ApplicationContext 測試支援整合。當您擴充套件 AbstractJUnit4SpringContextTests 時,您可以訪問一個 protectedapplicationContext 例項變數,您可以使用它來執行顯式 bean 查詢或測試整個上下文的狀態。

AbstractTransactionalJUnit4SpringContextTestsAbstractJUnit4SpringContextTests 的一個抽象事務擴充套件,它增加了一些方便的 JDBC 訪問功能。此類期望在 ApplicationContext 中定義 javax.sql.DataSource bean 和 PlatformTransactionManager bean。當您擴充套件 AbstractTransactionalJUnit4SpringContextTests 時,您可以訪問一個 protectedjdbcTemplate 例項變數,您可以使用它來執行 SQL 語句來查詢資料庫。您可以使用此類查詢來確認在執行資料庫相關應用程式程式碼之前和之後的資料庫狀態,並且 Spring 確保此類查詢在與應用程式程式碼相同的事務範圍內執行。與 ORM 工具結合使用時,請務必避免假陽性。如JDBC 測試支援中所述,AbstractTransactionalJUnit4SpringContextTests 還提供了委託給 JdbcTestUtils 中方法的便利方法,透過使用上述 jdbcTemplate。此外,AbstractTransactionalJUnit4SpringContextTests 提供了 executeSqlScript(..) 方法,用於針對配置的 DataSource 執行 SQL 指令碼。

這些類是為了方便擴充套件。如果您不想讓您的測試類繫結到 Spring 特定的類層次結構,您可以使用 @RunWith(SpringRunner.class)Spring 的 JUnit 規則配置您自己的自定義測試類。

TestNG 支援

org.springframework.test.context.testng 包為基於 TestNG 的測試用例提供了以下支援類:

  • AbstractTestNGSpringContextTests

  • AbstractTransactionalTestNGSpringContextTests

AbstractTestNGSpringContextTests 是一個抽象基類測試類,它將 Spring TestContext 框架與 TestNG 環境中的顯式 ApplicationContext 測試支援整合。當您擴充套件 AbstractTestNGSpringContextTests 時,您可以訪問一個 protectedapplicationContext 例項變數,您可以使用它來執行顯式 bean 查詢或測試整個上下文的狀態。

AbstractTransactionalTestNGSpringContextTestsAbstractTestNGSpringContextTests 的一個抽象事務擴充套件,它增加了一些方便的 JDBC 訪問功能。此類期望在 ApplicationContext 中定義 javax.sql.DataSource bean 和 PlatformTransactionManager bean。當您擴充套件 AbstractTransactionalTestNGSpringContextTests 時,您可以訪問一個 protectedjdbcTemplate 例項變數,您可以使用它來執行 SQL 語句來查詢資料庫。您可以使用此類查詢來確認在執行資料庫相關應用程式程式碼之前和之後的資料庫狀態,並且 Spring 確保此類查詢在與應用程式程式碼相同的事務範圍內執行。與 ORM 工具結合使用時,請務必避免假陽性。如JDBC 測試支援中所述,AbstractTransactionalTestNGSpringContextTests 還提供了委託給 JdbcTestUtils 中方法的便利方法,透過使用上述 jdbcTemplate。此外,AbstractTransactionalTestNGSpringContextTests 提供了 executeSqlScript(..) 方法,用於針對配置的 DataSource 執行 SQL 指令碼。

這些類是為了方便擴充套件。如果您不想讓您的測試類繫結到 Spring 特定的類層次結構,您可以使用 @ContextConfiguration@TestExecutionListeners 等配置您自己的自定義測試類,並透過 TestContextManager 手動檢測您的測試類。有關如何檢測測試類的示例,請參閱 AbstractTestNGSpringContextTests 的原始碼。
© . This site is unofficial and not affiliated with VMware.