号外!号外!号外!你的 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...
。
原文连接