使用測試屬性來源的內容組態
Spring Framework 對於具有屬性來源階層的環境概念提供一流的支援,您可以設定整合測試與測試專用的屬性來源。相較於 @Configuration
類別上使用的 @PropertySource
註解,您可以在測試類別上宣告 @TestPropertySource
註解,以宣告測試屬性檔案或內嵌屬性的資源位置。這些測試屬性來源會新增至 Environment
中 PropertySources
的集合,用於為已註解的整合測試載入的 ApplicationContext
。
您可以將
|
宣告測試屬性來源
您可以使用 @TestPropertySource
的 locations
或 value
屬性來設定測試屬性檔案。
依預設,同時支援傳統和基於 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 | 使用絕對路徑指定屬性檔案。 |
您可以使用 @TestPropertySource
的 properties
屬性,以金鑰值組的形式設定內嵌屬性,如下一個範例所示。所有金鑰值組都會以單一測試 PropertySource
新增至封閉的 Environment
,並具有最高優先順序。
金鑰值組的支援語法與 Java 屬性檔案中項目的定義語法相同
-
key=value
-
key:value
-
key 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
宣告為空註解 (也就是說,沒有 locations
或 properties
屬性的明確值),則會嘗試偵測相對於宣告註解之類別的預設屬性檔案。例如,如果已註解的測試類別為 com.example.MyTest
,則對應的預設屬性檔案為 classpath:com/example/MyTest.properties
。如果無法偵測到預設值,則會擲回 IllegalStateException
。
優先順序
測試屬性的優先順序高於作業系統環境、Java 系統屬性或應用程式透過使用 @PropertySource
以宣告方式或程式化方式新增的屬性來源中定義的屬性。因此,測試屬性可以用於選擇性地覆寫從系統和應用程式屬性來源載入的屬性。此外,內嵌屬性的優先順序高於從資源位置載入的屬性。但是請注意,透過 @DynamicPropertySource
註冊的屬性的優先順序高於透過 @TestPropertySource
載入的屬性。
在下一個範例中,timezone
和 port
屬性以及 "/test.properties"
中定義的任何屬性都會覆寫系統和應用程式屬性來源中定義的任何同名屬性。此外,如果 "/test.properties"
檔案定義了 timezone
和 port
屬性的項目,則這些項目會被使用 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
支援布林值 inheritLocations
和 inheritProperties
屬性,用於表示是否應繼承超類別宣告的屬性檔案和內嵌屬性的資源位置。這兩個旗標的預設值都是 true
。這表示測試類別會繼承任何超類別宣告的位置和內嵌屬性。具體而言,測試類別的位置和內嵌屬性會附加到超類別宣告的位置和內嵌屬性。因此,子類別可以選擇擴充位置和內嵌屬性。請注意,稍後出現的屬性會遮蔽 (也就是說,覆寫) 較早出現的同名屬性。此外,上述優先順序規則也適用於繼承的測試屬性來源。
如果 @TestPropertySource
中的 inheritLocations
或 inheritProperties
屬性設定為 false
,則測試類別的位置或內嵌屬性 (分別) 會遮蔽並有效地取代超類別定義的組態。
測試組態也可以從封閉類別繼承。如需詳細資訊,請參閱 @Nested 測試類別組態。 |
在下一個範例中,BaseTest
的 ApplicationContext
僅使用 base.properties
檔案作為測試屬性來源載入。相反地,ExtendedTest
的 ApplicationContext
使用 base.properties
和 extended.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() {
// ...
}
在下一個範例中,BaseTest
的 ApplicationContext
僅使用內嵌 key1
屬性載入。相反地,ExtendedTest
的 ApplicationContext
使用內嵌 key1
和 key2
屬性載入。以下範例示範如何使用內嵌屬性在子類別及其超類別中定義屬性
-
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() {
// ...
}