使用測試屬性源進行上下文配置

Spring Framework 對具有屬性源層次結構的環境概念提供了一流的支援,您可以使用特定於測試的屬性源配置整合測試。與在 @Configuration 類上使用的 @PropertySource 註解不同,您可以在測試類上宣告 @TestPropertySource 註解以宣告測試屬性檔案或內聯屬性的資源位置。這些測試屬性源被新增到為註解的整合測試載入的 ApplicationContextEnvironment 中的 PropertySources 集合中。

您可以將 @TestPropertySourceSmartContextLoader SPI 的任何實現一起使用,但 @TestPropertySource 不支援舊的 ContextLoader SPI 實現。

SmartContextLoader 的實現透過 MergedContextConfiguration 中的 getPropertySourceDescriptors()getPropertySourceProperties() 方法訪問合併的測試屬性源值。

宣告測試屬性源

您可以透過使用 @TestPropertySourcelocationsvalue 屬性來配置測試屬性檔案。

預設情況下,支援傳統和基於 XML 的 java.util.Properties 檔案格式——例如,"classpath:/com/example/test.properties""file:///path/to/file.xml"。從 Spring Framework 6.1 開始,您可以透過 @TestPropertySource 中的 factory 屬性配置自定義的 PropertySourceFactory,以支援不同的檔案格式,如 JSON、YAML 等。

每個路徑都被解釋為 Spring Resource。一個純路徑(例如,"test.properties")被視為相對於定義測試類的包的類路徑資源。以斜槓開頭的路徑被視為絕對類路徑資源(例如:"/org/example/test.xml")。引用 URL 的路徑(例如,以 classpath:file:http: 為字首的路徑)使用指定的資源協議載入。

路徑中的屬性佔位符(例如 ${…​})將根據 Environment 進行解析。

從 Spring Framework 6.1 開始,還支援資源位置模式——例如,"classpath*:/config/*.properties"

以下示例使用一個測試屬性檔案

  • Java

  • Kotlin

@ContextConfiguration
@TestPropertySource("/test.properties") (1)
class MyIntegrationTests {
	// class body...
}
1 指定一個帶絕對路徑的屬性檔案。
@ContextConfiguration
@TestPropertySource("/test.properties") (1)
class MyIntegrationTests {
	// class body...
}
1 指定一個帶絕對路徑的屬性檔案。

您可以使用 @TestPropertySourceproperties 屬性以鍵值對的形式配置內聯屬性,如下一個示例所示。所有鍵值對都作為具有最高優先順序的單個測試 PropertySource 新增到封閉的 Environment 中。

支援的鍵值對語法與 Java 屬性檔案中定義的條目語法相同

  • key=value

  • key:value

  • key value

儘管可以使用上述任何一種語法變體以及鍵和值之間的任意數量的空格來定義屬性,但建議您在測試套件中使用一種語法變體和一致的間距——例如,考慮始終使用 key = value 而不是 key= valuekey=value 等。同樣,如果您使用文字塊定義內聯屬性,則應在整個測試套件中始終使用文字塊來定義內聯屬性。

原因是您提供的確切字串將用於確定上下文快取的鍵。因此,為了從上下文快取中受益,您必須確保一致地定義內聯屬性。

以下示例設定了兩個內聯屬性

  • Java

  • Kotlin

@ContextConfiguration
@TestPropertySource(properties = {"timezone = GMT", "port = 4242"}) (1)
class MyIntegrationTests {
	// class body...
}
1 透過字串陣列設定兩個屬性。
@ContextConfiguration
@TestPropertySource(properties = ["timezone = GMT", "port = 4242"]) (1)
class MyIntegrationTests {
	// class body...
}
1 透過字串陣列設定兩個屬性。

從 Spring Framework 6.1 開始,您可以使用文字塊在單個 String 中定義多個內聯屬性。以下示例使用文字塊設定兩個內聯屬性

  • Java

  • Kotlin

@ContextConfiguration
@TestPropertySource(properties = """
	timezone = GMT
	port = 4242
	""") (1)
class MyIntegrationTests {
	// class body...
}
1 透過文字塊設定兩個屬性。
@ContextConfiguration
@TestPropertySource(properties = ["""
	timezone = GMT
	port = 4242
	"""]) (1)
class MyIntegrationTests {
	// class body...
}
1 透過文字塊設定兩個屬性。

@TestPropertySource 可以用作可重複註解

這意味著您可以在單個測試類上擁有多個 @TestPropertySource 宣告,後來的 @TestPropertySource 註解中的 locationsproperties 將覆蓋以前的 @TestPropertySource 註解中的內容。

此外,您可以在測試類上宣告多個組合註解,每個註解都用 @TestPropertySource 進行元註解,所有這些 @TestPropertySource 宣告都將對您的測試屬性源做出貢獻。

直接存在的 @TestPropertySource 註解始終優先於元存在的 @TestPropertySource 註解。換句話說,直接存在的 @TestPropertySource 註解中的 locationsproperties 將覆蓋用作元註解的 @TestPropertySource 註解中的 locationsproperties

預設屬性檔案檢測

如果 @TestPropertySource 被宣告為空註解(即,沒有為 locationsproperties 屬性顯式賦值),則會嘗試檢測相對於宣告該註解的類的預設屬性檔案。例如,如果註解的測試類是 com.example.MyTest,則相應的預設屬性檔案是 classpath:com/example/MyTest.properties。如果無法檢測到預設值,則會丟擲 IllegalStateException

優先順序

測試屬性的優先順序高於作業系統環境、Java 系統屬性或應用程式透過宣告式使用 @PropertySource 或程式設計方式新增的屬性源中定義的屬性。因此,測試屬性可用於選擇性地覆蓋從系統和應用程式屬性源載入的屬性。此外,內聯屬性的優先順序高於從資源位置載入的屬性。但是,請注意,透過 @DynamicPropertySource 註冊的屬性的優先順序高於透過 @TestPropertySource 載入的屬性。

在下一個示例中,timezoneport 屬性以及 "/test.properties" 中定義的任何屬性將覆蓋在系統和應用程式屬性源中定義的同名屬性。此外,如果 "/test.properties" 檔案定義了 timezoneport 屬性的條目,則這些條目將被使用 properties 屬性宣告的內聯屬性覆蓋。以下示例顯示瞭如何在檔案和內聯中同時指定屬性

  • Java

  • Kotlin

@ContextConfiguration
@TestPropertySource(
	locations = "/test.properties",
	properties = {"timezone = GMT", "port = 4242"}
)
class MyIntegrationTests {
	// class body...
}
@ContextConfiguration
@TestPropertySource("/test.properties",
		properties = ["timezone = GMT", "port = 4242"]
)
class MyIntegrationTests {
	// class body...
}

繼承和覆蓋測試屬性源

@TestPropertySource 支援布林型 inheritLocationsinheritProperties 屬性,它們表示是否應繼承超類宣告的屬性檔案資源位置和內聯屬性。這兩個標誌的預設值都為 true。這意味著測試類繼承任何超類宣告的位置和內聯屬性。具體來說,測試類位置和內聯屬性將附加到超類宣告的位置和內聯屬性之後。因此,子類可以選擇擴充套件位置和內聯屬性。請注意,後出現的屬性會遮蔽(即覆蓋)先出現的同名屬性。此外,上述優先順序規則也適用於繼承的測試屬性源。

如果 @TestPropertySource 中的 inheritLocationsinheritProperties 屬性設定為 false,則測試類的位置或內聯屬性將分別遮蔽並有效地替換超類定義的配置。

測試配置也可以從封閉類繼承。詳情請參閱@Nested 測試類配置

在下一個示例中,BaseTestApplicationContext 僅使用 base.properties 檔案作為測試屬性源載入。相比之下,ExtendedTestApplicationContext 使用 base.propertiesextended.properties 檔案作為測試屬性源位置載入。以下示例展示瞭如何使用 properties 檔案在子類及其超類中定義屬性

  • Java

  • Kotlin

@TestPropertySource("base.properties")
@ContextConfiguration
class BaseTest {
	// ...
}

@TestPropertySource("extended.properties")
@ContextConfiguration
class ExtendedTest extends BaseTest {
	// ...
}
@TestPropertySource("base.properties")
@ContextConfiguration
open class BaseTest {
	// ...
}

@TestPropertySource("extended.properties")
@ContextConfiguration
class ExtendedTest : BaseTest() {
	// ...
}

在下一個示例中,BaseTestApplicationContext 僅使用內聯的 key1 屬性載入。相比之下,ExtendedTestApplicationContext 使用內聯的 key1key2 屬性載入。以下示例展示瞭如何使用內聯屬性在子類及其超類中定義屬性

  • Java

  • Kotlin

@TestPropertySource(properties = "key1 = value1")
@ContextConfiguration
class BaseTest {
	// ...
}

@TestPropertySource(properties = "key2 = value2")
@ContextConfiguration
class ExtendedTest extends BaseTest {
	// ...
}
@TestPropertySource(properties = ["key1 = value1"])
@ContextConfiguration
open class BaseTest {
	// ...
}

@TestPropertySource(properties = ["key2 = value2"])
@ContextConfiguration
class ExtendedTest : BaseTest() {
	// ...
}
© . This site is unofficial and not affiliated with VMware.