使用測試屬性源的上下文配置
Spring Framework 對具有屬性源層級結構的環境概念提供一流的支援,您可以使用測試專用的屬性源配置整合測試。與 @Configuration
類上使用的 @PropertySource
註解不同,您可以在測試類上宣告 @TestPropertySource
註解,以宣告測試屬性檔案或內聯屬性的資源位置。這些測試屬性源將被新增到為帶註解的整合測試載入的 ApplicationContext
的 Environment
中的 PropertySources
集合中。
您可以將
|
宣告測試屬性源
您可以使用 @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
。這意味著測試類會繼承任何超類宣告的位置和內聯屬性。具體來說,測試類的位置和內聯屬性將附加到超類宣告的位置和內聯屬性之後。因此,子類可以選擇擴充套件位置和內聯屬性。請注意,後出現的屬性會覆蓋(即 shadow)先出現的同名屬性。此外,上述優先順序規則也適用於繼承的測試屬性源。
如果 @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() {
// ...
}