上下文快取

一旦 TestContext 框架為測試載入了 ApplicationContext(或 WebApplicationContext),該上下文就會被快取並重用於在同一測試套件中宣告相同唯一上下文配置的所有後續測試。要理解快取的工作原理,理解“唯一”和“測試套件”的含義至關重要。

ApplicationContext 可以透過用於載入它的配置引數組合來唯一標識。因此,配置引數的唯一組合用於生成一個鍵,在該鍵下快取上下文。TestContext 框架使用以下配置引數來構建上下文快取鍵

  • locations(來自 @ContextConfiguration

  • classes(來自 @ContextConfiguration

  • contextInitializerClasses(來自 @ContextConfiguration

  • contextCustomizers(來自 ContextCustomizerFactory)——這包括 @DynamicPropertySource 方法、Bean 覆蓋(例如 @TestBean@MockitoBean@MockitoSpyBean 等)以及 Spring Boot 測試支援中的各種功能。

  • contextLoader(來自 @ContextConfiguration

  • parent(來自 @ContextHierarchy

  • activeProfiles(來自 @ActiveProfiles

  • propertySourceDescriptors(來自 @TestPropertySource

  • propertySourceProperties(來自 @TestPropertySource

  • resourceBasePath(來自 @WebAppConfiguration

例如,如果 TestClassA@ContextConfigurationlocations(或 value)屬性指定 {"app-config.xml", "test-config.xml"},則 TestContext 框架會載入相應的 ApplicationContext 並將其儲存在基於這些位置的鍵下的 static 上下文快取中。因此,如果 TestClassB 也為其位置(透過繼承顯式或隱式地)定義 {"app-config.xml", "test-config.xml"},但未定義 @WebAppConfiguration、不同的 ContextLoader、不同的活動配置檔案、不同的上下文初始化器、不同的上下文定製器、不同的測試或動態屬性源,或不同的父上下文,那麼相同的 ApplicationContext 將由兩個測試類共享。這意味著載入應用程式上下文的設定成本只需承擔一次(每個測試套件),並且後續測試執行會快得多。

測試套件和分叉程序

Spring TestContext 框架將應用程式上下文儲存在靜態快取中。這意味著上下文實際上儲存在 static 變數中。換句話說,如果測試在單獨的程序中執行,靜態快取會在每次測試執行之間清除,從而有效地停用快取機制。

為了受益於快取機制,所有測試必須在同一程序或測試套件中執行。這可以透過在 IDE 中將所有測試作為一個組執行來實現。同樣,當使用 Ant、Maven 或 Gradle 等構建框架執行測試時,務必確保構建框架不會在測試之間進行分叉。例如,如果 Maven Surefire 外掛的 forkMode 設定為 alwayspertest,則 TestContext 框架無法在測試類之間快取應用程式上下文,因此構建過程會顯著變慢。

上下文快取的大小受到限制,預設最大大小為 32。每當達到最大大小時,就會使用最近最少使用(LRU)逐出策略逐出並關閉陳舊的上下文。您可以透過設定名為 spring.test.context.cache.maxSize 的 JVM 系統屬性從命令列或構建指令碼配置最大大小。作為替代方案,您可以透過 SpringProperties 機制設定相同的屬性。

自 Spring Framework 7.0 起,儲存在上下文快取中的應用程式上下文在不再活動使用時將被暫停,並在下次從快取中檢索上下文時自動重新啟動。具體來說,後者將重新啟動應用程式上下文中所有自動啟動的 Bean,有效地恢復生命週期狀態。這確保了在上下文未被測試使用時,上下文中的後臺程序不會主動執行。例如,JMS 監聽器容器、計劃任務以及上下文中實現 LifecycleSmartLifecycle 的任何其他元件將處於“停止”狀態,直到上下文再次被測試使用。但是請注意,SmartLifecycle 元件可以透過從 SmartLifecycle#isPauseable() 返回 false 來選擇不暫停。

由於在給定測試套件中載入大量應用程式上下文可能會導致套件執行時間過長,因此瞭解已載入和快取的上下文數量通常是有益的。要檢視底層上下文快取的統計資訊,您可以將 org.springframework.test.context.cache 日誌記錄類別的日誌級別設定為 DEBUG

在極少數情況下,測試會損壞應用程式上下文並需要重新載入(例如,透過修改 Bean 定義或應用程式物件的狀態),您可以使用 @DirtiesContext 註解您的測試類或測試方法(請參閱 Spring 測試註解中關於 @DirtiesContext 的討論)。這會指示 Spring 從快取中移除上下文並在執行下一個需要相同應用程式上下文的測試之前重建應用程式上下文。請注意,對 @DirtiesContext 註解的支援由 DirtiesContextBeforeModesTestExecutionListenerDirtiesContextTestExecutionListener 提供,它們預設啟用。

ApplicationContext 生命週期和控制檯日誌記錄

當您需要除錯使用 Spring TestContext 框架執行的測試時,分析控制檯輸出(即,輸出到 SYSOUTSYSERR 流)可能很有用。一些構建工具和 IDE 能夠將控制檯輸出與給定測試相關聯;但是,一些控制檯輸出無法輕易與給定測試相關聯。

關於由 Spring 框架本身或在 ApplicationContext 中註冊的元件觸發的控制檯日誌記錄,瞭解由 Spring TestContext 框架在測試套件中載入的 ApplicationContext 的生命週期非常重要。

測試的 ApplicationContext 通常在準備測試類例項時載入——例如,對測試例項的 @Autowired 欄位執行依賴注入。這意味著在 ApplicationContext 初始化期間觸發的任何控制檯日誌記錄通常無法與單個測試方法相關聯。但是,如果上下文根據 @DirtiesContext 語義在測試方法執行之前立即關閉,則將在測試方法執行之前載入上下文的新例項。在後一種情況下,IDE 或構建工具可能會將控制檯日誌記錄與單個測試方法相關聯。

測試的 ApplicationContext 可以透過以下情況之一關閉。

  • 上下文根據 @DirtiesContext 語義關閉。

  • 上下文關閉是因為它已根據 LRU 逐出策略自動從快取中逐出。

  • 當測試套件的 JVM 終止時,上下文透過 JVM 關閉鉤子關閉。

如果上下文在特定測試方法之後根據 @DirtiesContext 語義關閉,IDE 或構建工具可能會將控制檯日誌記錄與單個測試方法相關聯。如果上下文在測試類之後根據 @DirtiesContext 語義關閉,則在 ApplicationContext 關閉期間觸發的任何控制檯日誌記錄都無法與單個測試方法相關聯。同樣,透過 JVM 關閉鉤子在關閉階段觸發的任何控制檯日誌記錄也無法與單個測試方法相關聯。

當 Spring ApplicationContext 透過 JVM 關閉鉤子關閉時,在關閉階段執行的回撥在名為 SpringContextShutdownHook 的執行緒上執行。因此,如果您希望停用在 ApplicationContext 透過 JVM 關閉鉤子關閉時觸發的控制檯日誌記錄,您可以在日誌記錄框架中註冊一個自定義過濾器,允許您忽略由該執行緒發起的任何日誌記錄。

© . This site is unofficial and not affiliated with VMware.