Context Hierarchies
當編寫依賴已載入 Spring ApplicationContext
的整合測試時,通常針對單一 context 進行測試就已足夠。然而,有時針對 ApplicationContext
實例的階層結構進行測試會更有益,甚至有其必要性。例如,如果您正在開發 Spring MVC Web 應用程式,您通常會有一個由 Spring 的 ContextLoaderListener
載入的根 WebApplicationContext
,以及一個由 Spring 的 DispatcherServlet
載入的子 WebApplicationContext
。這會產生一個父子 context 階層結構,其中共用的元件和基礎架構組態會在根 context 中宣告,並由 Web 專用元件在子 context 中取用。另一個用例可以在 Spring Batch 應用程式中找到,您通常會有一個父 context 提供共用批次基礎架構的組態,以及一個子 context 提供特定批次作業的組態。
您可以透過使用 @ContextHierarchy
註解宣告 context 組態,來編寫使用 context 階層結構的整合測試,無論是在個別測試類別上還是測試類別階層結構中。如果 context 階層結構在測試類別階層結構中的多個類別上宣告,您也可以合併或覆寫 context 階層結構中特定、已命名層級的 context 組態。當合併階層結構中給定層級的組態時,組態資源類型(即 XML 組態檔或元件類別)必須一致。否則,context 階層結構中使用不同資源類型組態的不同層級是完全可以接受的。
本節中剩餘基於 JUnit Jupiter 的範例,展示了整合測試的常見組態情境,這些測試需要使用 context 階層結構。
具有 context 階層結構的單一測試類別
ControllerIntegrationTests
代表 Spring MVC Web 應用程式的典型整合測試情境,透過宣告一個包含兩個層級的 context 階層結構,一個用於根 WebApplicationContext
(使用 TestAppConfig
@Configuration
類別載入),另一個用於 dispatcher servlet WebApplicationContext
(使用 WebConfig
@Configuration
類別載入)。自動裝配到測試實例中的 WebApplicationContext
是子 context 的那個(即階層結構中最低的 context)。以下清單顯示了此組態情境
-
Java
-
Kotlin
@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@ContextHierarchy({
@ContextConfiguration(classes = TestAppConfig.class),
@ContextConfiguration(classes = WebConfig.class)
})
class ControllerIntegrationTests {
@Autowired
WebApplicationContext wac;
// ...
}
@ExtendWith(SpringExtension::class)
@WebAppConfiguration
@ContextHierarchy(
ContextConfiguration(classes = [TestAppConfig::class]),
ContextConfiguration(classes = [WebConfig::class]))
class ControllerIntegrationTests {
@Autowired
lateinit var wac: WebApplicationContext
// ...
}
具有隱含父 context 的類別階層結構
此範例中的測試類別在測試類別階層結構中定義了一個 context 階層結構。AbstractWebTests
在 Spring 驅動的 Web 應用程式中宣告了根 WebApplicationContext
的組態。但是請注意,AbstractWebTests
未宣告 @ContextHierarchy
。因此,AbstractWebTests
的子類別可以選擇性地參與 context 階層結構,或遵循 @ContextConfiguration
的標準語意。SoapWebServiceTests
和 RestWebServiceTests
都擴展了 AbstractWebTests
,並透過使用 @ContextHierarchy
定義了一個 context 階層結構。結果是載入了三個應用程式 context(每個 @ContextConfiguration
宣告一個),並且基於 AbstractWebTests
組態載入的應用程式 context 被設定為為具體子類別載入的每個 context 的父 context。以下清單顯示了此組態情境
-
Java
-
Kotlin
@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@ContextConfiguration("file:src/main/webapp/WEB-INF/applicationContext.xml")
public abstract class AbstractWebTests {}
@ContextHierarchy(@ContextConfiguration("/spring/soap-ws-config.xml"))
public class SoapWebServiceTests extends AbstractWebTests {}
@ContextHierarchy(@ContextConfiguration("/spring/rest-ws-config.xml"))
public class RestWebServiceTests extends AbstractWebTests {}
@ExtendWith(SpringExtension::class)
@WebAppConfiguration
@ContextConfiguration("file:src/main/webapp/WEB-INF/applicationContext.xml")
abstract class AbstractWebTests
@ContextHierarchy(ContextConfiguration("/spring/soap-ws-config.xml"))
class SoapWebServiceTests : AbstractWebTests()
@ContextHierarchy(ContextConfiguration("/spring/rest-ws-config.xml"))
class RestWebServiceTests : AbstractWebTests()
具有合併 context 階層結構組態的類別階層結構
此範例中的類別顯示了如何使用已命名的階層結構層級,以便合併 context 階層結構中特定層級的組態。BaseTests
在階層結構中定義了兩個層級,parent
和 child
。ExtendedTests
擴展了 BaseTests
,並指示 Spring TestContext Framework 合併 child
階層結構層級的 context 組態,方法是確保在 @ContextConfiguration
中的 name
屬性中宣告的名稱都是 child
。結果是載入了三個應用程式 context:一個用於 /app-config.xml
,一個用於 /user-config.xml
,以及一個用於 {"/user-config.xml", "/order-config.xml"}
。與先前的範例一樣,從 /app-config.xml
載入的應用程式 context 被設定為從 /user-config.xml
和 {"/user-config.xml", "/order-config.xml"}
載入的 context 的父 context。以下清單顯示了此組態情境
-
Java
-
Kotlin
@ExtendWith(SpringExtension.class)
@ContextHierarchy({
@ContextConfiguration(name = "parent", locations = "/app-config.xml"),
@ContextConfiguration(name = "child", locations = "/user-config.xml")
})
class BaseTests {}
@ContextHierarchy(
@ContextConfiguration(name = "child", locations = "/order-config.xml")
)
class ExtendedTests extends BaseTests {}
@ExtendWith(SpringExtension::class)
@ContextHierarchy(
ContextConfiguration(name = "parent", locations = ["/app-config.xml"]),
ContextConfiguration(name = "child", locations = ["/user-config.xml"]))
open class BaseTests {}
@ContextHierarchy(
ContextConfiguration(name = "child", locations = ["/order-config.xml"])
)
class ExtendedTests : BaseTests() {}
具有覆寫 context 階層結構組態的類別階層結構
與先前的範例相反,此範例示範了如何透過將 @ContextConfiguration
中的 inheritLocations
旗標設定為 false
,來覆寫 context 階層結構中給定已命名層級的組態。因此,ExtendedTests
的應用程式 context 僅從 /test-user-config.xml
載入,並且其父 context 設定為從 /app-config.xml
載入的 context。以下清單顯示了此組態情境
-
Java
-
Kotlin
@ExtendWith(SpringExtension.class)
@ContextHierarchy({
@ContextConfiguration(name = "parent", locations = "/app-config.xml"),
@ContextConfiguration(name = "child", locations = "/user-config.xml")
})
class BaseTests {}
@ContextHierarchy(
@ContextConfiguration(
name = "child",
locations = "/test-user-config.xml",
inheritLocations = false
))
class ExtendedTests extends BaseTests {}
@ExtendWith(SpringExtension::class)
@ContextHierarchy(
ContextConfiguration(name = "parent", locations = ["/app-config.xml"]),
ContextConfiguration(name = "child", locations = ["/user-config.xml"]))
open class BaseTests {}
@ContextHierarchy(
ContextConfiguration(
name = "child",
locations = ["/test-user-config.xml"],
inheritLocations = false
))
class ExtendedTests : BaseTests() {}
在 context 階層結構中弄髒 context 如果您在測試中使用 @DirtiesContext ,而該測試的 context 組態為 context 階層結構的一部分,則可以使用 hierarchyMode 旗標來控制 context 快取清除的方式。如需更多詳細資訊,請參閱 Spring 測試註解 和 @DirtiesContext javadoc 中關於 @DirtiesContext 的討論。 |