號外!號外!號外!你的 spring boot integration tests
運行慢嗎,是否是每跑一次測試,你都在等待,等待它全綠的那一瞬間。若是你遇到,那請接着往下看,也許能夠幫助到你。若是你沒有遇到,那也請往下看,由於也許之後你會遇到。html
告訴你一個祕密:@MockBean
會致使測試類(Test Class)之間spring boot application context
不斷啓動屢次!!!java
不信,那麼咱們請看栗子 MockBean Annotation:git
這項目有兩個測試類,AboutControllerTest 和 TokenControllerTestgithub
AccountControllerTest:redis
TokenControllerTest:spring
AccountControllerTest
沒有使用 @MockBean
,TokenControllerTest
使用 @MockBean
。下面是兩個測試一塊兒運行產生的日誌:api
如上圖所示,spring boot
啓動兩次。而spring boot
的啓動時間也比較耗時,因此@MockBean
,頗有可能致使測試運行的很慢。那@MockBean
究竟是個怎麼樣的存在?緩存
寫過spring boot integration test
的小夥伴,對於@MockBean
應該會比較熟悉。在寫測試時,對於一些應用的外部依賴須要進行一些Mock
處理,好比:Redis
、ElasticSearch
、ExternalService
等。官方文檔介紹 Mocking and spying beans:app
- It allows to add Mockito mocks in a Spring ApplicationContext.
- If a bean, compatible with the declared class exists in the context, it replaces it by the mock.
- If it is not the case, it adds the mock in the context as a bean.
也就是說,@MockBean
會改變spring boot application context beans
,致使使用了@MockBean
的測試類之間的須要不一樣application context
,從而致使spring boot application context
重啓。爲何須要不一樣application context
就須要重啓???帶着疑惑,咱們接着往下看。spring-boot
什麼是application context
?簡單理解,就是應用程序運行所須要的上下文。官方文檔介紹 Context Management:
官方文檔介紹 Context management and caching:
根據官方文檔意思,application context
爲初始化測試實例提供上下文,若是須要不一樣的application context
實例化不一樣的測試,就須要從新啓動spring boot
,建立不一樣applicaiton context
。文檔還說到,爲了解決spring boot application context
啓動慢的問題,會作緩存處理。那@MockBean
到底破壞了什麼樣的緩存規則,從而致使spring boot
重啓屢次?是什麼致使打開方式出了問題?
要回答這個問題,就要先了解application context caching
的uniquely key
包含的內容,附上官方文檔介紹 Context caching:
根據文檔的描述,不難知道application context cacheing
是經過key:value
方式進行緩存的,惟一鍵爲組合鍵,包含:locations、classes、contextInitializerClasses、contextCustomizers、contextLoader、parent、activeProfiles、propertySourceLocations、propertySourceProperties、resourceBasePath
。
而@MockBean
的使用會致使每一個application context
中contextCustomizer
的不一樣,從而致使存儲在context cache
中的application context
的uniquely key
不一樣,最終致使application context
在測試類之間不能共享。雖然沒有官方文檔說明這一點,不過在
org.springframework.boot.test.mock.mockito.MockitoContextCustomizerFactory 源代碼中能夠找到一些痕跡:
圖中所說的MergedContextConfiguration
就是application context caching
的uniquely key
。
對於spring boot integration test
來講,除了 external service(clients...)
須要被 Mock
,其它的內部依賴(service、repository…)都不該該被Mock
。external service
能夠在配置層,進行Mock
,而後在測試類中,直接經過@Auotwrite
方式注入:
RedisTemplateBeanConfigurationMocker:
TokenControllerTest
,直接 @Autowrite RedisTemplateBeanConfigurationMocker
中配置的,RedisTemplate @Bean
。完成栗子,請查mockbean-annotation。
spring boot integration test
相對於 api test
,應該更關注api
功能的完整性,瞭解依賴的邊界,不須要Mock
的,就不要Mock
,好比:service, repository…
。對於外部依賴,統一在配置層完成 Mock
,好比:client、redis、rabbitmq...
。
原文連接