SpringBoot單元測試:MockMvc的自動配置
MockMvc 的自動配置
上面我們提到@AutoConfigureMockMvc 提供了自動配置 MockMvc 的功能,實例化MockMvc 的
具 體 代 碼 在
spring-boot-test-autoconfigure 項 目 中 的MockMvcAutoConfiguration 自 動 配 置 類 內(nèi) 。而 該 自 動 配 置 類 的 生 效 又 涉 及 了@AutoConfigureMockMvc 注解。本節(jié)我們就大致來了解一下@AutoConfigureMockMvc 和MockMvcAutoConfiguration。
AutoConfigureMockMvc 注解
上節(jié)的例子中使用@AutoConfigureMockMvc 注解來引入啟動單元測試的自動注入,從而注入 MockMvc 類的 Bean。那么,@AutoConfigureMockMvc 只是注入了 MockMvc 的 Bean嗎?并不是的,我們來看一下
@AutoConfigureMockMvc 的源代碼。
@Target({ ElementType . TYPE,ElementType .METHOD })
@Retent ion(RetentionPolicy . RUNTIME)@Documented
@Inherited
@ImportAutoConfiguration
@PropertyMapping(" spring. test . mockmvc")
public @interface AutoConfigureMockMvc {
//是否應(yīng)向 MockMVC 注冊來自應(yīng)用程序上下文的 filter,默認為 true
boolean addFilters() default true;
// 每次 MockMVC 調(diào)用后應(yīng)如何打 EMvcResult 信息
@PropertyMapping(skip = SkipPropertyMapping .ON DEFAULT _VALUE)
MockMvcPrint print() default MockMvcPrint . DEFAULT;
//如果 MvcResult 僅在測試失敗時才打印信息。true,則表示只在失敗時打印
boolean printOnlyOnFailure() default true;
/當 HtmUnit 在類路徑上時, 是否應(yīng)該自動配置 webCliento 默認為 true
@PropertyMapping( "webclient . enabled")
boolean webClientEnabled() default true;
//當 Selenium 位于類路徑上時,是否應(yīng)自動配置 WebDriver。默認 為 true
@PropertyMapping("webdriver . enabled")
boolean webDriverEnabled() default true;
}AutoConfigureMockMvc 中定義的屬性比較簡單,除了 print 屬性是用于配置每次 MockMVC調(diào)用后打印 MvcResult 信息之外,其余的配置均為設(shè)置特定情況下是否進行相應(yīng)處理??山Y(jié)合上述代碼中的注釋部分了解對應(yīng)屬性的詳細功能。同時,在上節(jié)的實例中(也是通常情況下)我們并沒有進行特殊的配置,都采用該注解中的默認值。
在 AutoConfigureMockMvc 的源碼中,我們重點看它組合的@ImportAutoConfiguration 注解 。該 注 解 同 樣 是 Spring Boot 自 動 配 置 項 目 提 供 的 , 其 功 能 類 似@EnableAutoCon-figuration,但又略有區(qū)別。
@lmportAutoConfiguration 同樣用于導(dǎo)入自動配置類,不僅可以像@EnableAutoConfiguration 那樣排除指定的自動配置類,還可以指定使用哪些自動配置類,這是它們之間的重要區(qū)別之一。
另外,@ImportAutoConfiguration 使用的排序規(guī)則與
@EnableAutoConfiguration 的相同,通常情況下,建議優(yōu)先使用
@EnableAutoConfiguration 注解進行自動配置。但在單元測試中,則可考慮優(yōu)先使用
@lmportAutoConfiguration。下面看 一下它的源碼及功能,代碼如下。
@Target(ElementType . TYPE)
@Retention( RetentionPolicy . RUNTIME)
@Documented@Inherited
@Import( ImportAutoConfigurationImportSelector. class)
public @interface ImportAutoConfiguration {
//指定引入的自動配置類
@AliasFor("classes")
Class>[] value() default {};
//指定引入的自動配置類。如果為空,則使用 ME TA- INF/spring. factories 中注冊的指定類
//其中 spring. factories 中注冊的 key 為被該注解的類的全限定名稱
@AliasFor("value")
Class>[] classes() default {};
/排除指定自動配置類
Class>[] exclude() default {};
}上述代碼中關(guān)于 ImportAutoConfiguration 導(dǎo)入的 Selector 與之前講解@EnableAuto-Configuration 時的使用流程基本一致,我們不再贅述。
下面來看 ImportAutoConfiguration 中定義的屬性。通過 value 屬性,提供了指定自動配置類 的 功 能 , 可 以 通 過 細 粒 度 控 制 , 根 據(jù) 需 要 引 | 入 相 應(yīng) 功 能 的 自 動 配 置 。沒 有@EnableAutoConfiguration-次注入全局生效的特性,但是有了指定的靈活性。
更值得注意的是 classes 屬性,它也是用來指定自動配置類的,但它的特殊之處在于,如果未進行指定,則會默認搜索項目 ME TA-INF/spring.factories 文件中注冊的類,但是它搜索的注冊類在 spring.factories 中的 key 是被@ImportAutoConfiguration 注解的類的全限定名稱。顯然,這里的 key 為 org.springframework.
boot.test.autoconfigure.web.servlet.Auto-ConfigureMockMvc 。以 上 功 能 也 就 解 釋 了 為 什 么 在 單 元 測 試 中 更 多 的 是 使 用@lmportAuto-Configuration 注解來進行自動配置了。
在
spring-boot-test-autoconfigure 項目的 spring.factories 文件中的相關(guān)配置如下。
# AutoConfigureMockMvc auto-configuration imports
org. springframework . boot . test . autoconfigure . web. servlet . AutoConf igureMockMv
org. springframework. boot . test . autoconfigure . web . servlet . MockMvcAutoConfigur
ation, \
org. springframework . boot . test . autoconfigure . web . servlet . MockMvcWebClientAut
oCon-
figuration, \
org . springframework. boot . test. autoconfigure . web . servlet. MockMvcWebDriverAut
oCon-
figuration, \
org. springframework . boot . autoconfigure . security. servlet. SecurityAutoConfiguration,\
org. springframework . boot . autoconfigure . security . servlet . UserDetailsServiceA
uto-
Configuration, \
org. springframework. boot . test . autoconfigure . web . servlet . MockMvcSecurity
Configuration也就是說,當使用@lmportAutoConfiguration 注解,并未指定 classes 屬性值時,默認自動配置上述自動配置類。
關(guān) 于 @ImportAutoConfiguration 我 們 就 講 這 么 多 , 讀 者 朋 友 可 以 對 照@EnableAuto-Configuration 相關(guān)章節(jié)中提供的方法,當作練習(xí)自行閱讀該注解導(dǎo)入的
ImportAutoConfi-gurationlmportSelector。下節(jié)我們以配置中的 MockMvcAutoConfiguration為例,講解 MockMvc 相關(guān)的自動化配置。

?MockMvcAutoConfiguration 自動配置
上 一 節(jié) 我 們 知 道 通 過 使 用 @AutoConfigureMockMvc 注 解 會 導(dǎo) 入MockMvcAutoCon-figuration 自動配置類,該類就是專門為 MockMvc 相關(guān)功能提供自動配置的。
先看 MockMvcAutoConfiguration 的注解和構(gòu)造方法部分源代碼。
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type . SERVLET)
@AutoConfigureAfter (WebMvcAutoConfiguration. class)
@EnableConfigurationProperties({ ServerProperties. class, WebMvcProperties.c
lass } )
public class MockMvcAutoConfiguration {
private final WebApplicationContext context;
private final WebMvcProperties webMvcProperties;
MockMvcAutoConfiguration(WebApplicationContext context, WebMvcProperties
webMvcProperties) {
this. context = context;
this
. webM
Properties = webMvcProperties; }}注解部分說明,MockMvcAutoConfiguration 需 要在 Web 應(yīng)用程序類型為 Servlet,且在WebMvcAutoConfiguration 自 動配置之后進行自動配置。關(guān)于 WebMvcAutoConfiguration我們在前面章節(jié)已經(jīng)講到,這里不再贅述。另 外 , 通 過 @
EnableConfigurationProperties 導(dǎo) 入 了 ServerProperties 和WebMvcProperties 兩個配置屬性類,并通過構(gòu)造方法設(shè)置為成員變量。
下面挑選 MockMvcAutoConfiguration 中幾個比較重要的自動配置 Bean 來進行講解,首先看 DispatcherServletPath 的注入。
@Bean
@Condit ional0nMi ssingBean
public DispatcherServletPath dispatcherServletPath() {
return () -> this . webMvcProperties . getServlet() . getPath();}當容器中不存在 DispatcherServletPath 的 Bean 時,會創(chuàng)建一個 DispatcherServletPath 實現(xiàn) 類 的 對 象 , 并 注 入 容 器 。其 中 DispatcherServletPath 是 一 個 接 口 , 用 來 提 供DispatcherServlet 所需路徑的詳細信息。在上述代碼中實現(xiàn)了 DispatcherServletPath 的getPath 方法,并返回 WebMvcProperties 配置:文件默認(“") 或指定的 Web 訪問路徑。
MockMvc 主 要 是 通 過 MockMvcBuilder 創(chuàng) 建 的 , 默 認 情 況 下 實 例 化 了DefaultMock-MvcBuilder,相關(guān)代碼如下。
@Bean
@Conditional0nMi ssingBean(MockMvcBuilder . class)
public DefaultMockMvcBuilder mockMvcBuilder(List
customizers) {
DefaultMockMvcBuilder builder = MockMvcBuilders . webAppContextSetup(this. (
ontext) ;
builder . addDispatcherServletCustomizer (new MockMvcDi spatcherServletCusto-
mizer(this . webMvcProperties));
for (MockMvcBuilderCustomizer customizer : customizers) {
customizer. customize(builder);}
return builder;}當 容 器 中 不 存 在 MockMvcBuilder 的 Bean 時 , 通 過 MockMvcBuilders 的webAppContextSetup 方法創(chuàng)建 DefaultMockMvcBuilder ,然后設(shè)置 DispatcherServlet 和MockMvcBuilder 的 定 制 化 配 置 。其 中 , 關(guān) 于 DispatcherServlet 的 設(shè) 置 就 在MockMvcAutoConfiguration 中定義,其核心代碼如下。
@Override
public void customize(DispatcherServlet dispatcherServlet) {
dispatcherServlet . setDispatchOptionsRequest(this . webMvcProperties . isDispa
tch-
Opt ionsRequest());
dispatcherServlet . setDi spatchTraceRequest(this . webMvcProperties . isDispa-tchTraceRequest());
dispatcherServlet
. setThrowExceptionIfNoHandlerFound( this . webMvcProperties . isThrowExcep-
tionIfNoHandlerFound());
}上述代碼就是對配置文件 WebMvcProperties 中 DispatcherServlet 是 否 分 發(fā)“HTTPOPTIONS"請求、是否分發(fā)“HTTPTRACE"、是否拋出 NoHandlerFoundException進行配置。
當獲得了 MockMvcBuilder,便可以配置并實例化 MockMvc 了,相關(guān)代碼如下。
@Bean
@ConditionalOnMi ssingBean
public MockMvc mockMvc (MockMvcBuilder builder) {
return builder . build(); }至此,MockMvc 已經(jīng)被實例化并注入容器了。當然,如果容器中不存在 DispatcherServlet對應(yīng)的 Bean, 也會進行相應(yīng)的自動配置。
@Bean
@ConditionalOnMissingBean
public
Di spatcherServlet dispatcherServlet (MockMvc mockMvc) {
return mockMvc . getDispatcherServlet();
}這里是通過 MockMvc 提供的方法來獲得 DispatcherServlet 的 Bean,并注冊。
正是有了上述自動配置機制,我們在單元測試時直接在單元測試類上使用@AutoCon-figureMockMvc 注解之后,便可以直接通過@Autowired 對 MockMvc 進行注入并使用了。

小結(jié)
本章簡單地介紹了 Spring Boot 中對單元測試的支持,以及常用的注解、單元測試實例。關(guān)于單元測試開啟及自動注入我們講解了@AutoConfigureMockMvc。類似的,Spring Boot還提供了許多更加有針對性、使用快捷的注解,比如:針對 JSON 的@JsonTest、 針對 MVC的@WebMvcTest、針對 WebFlux 的@WebFluxTest、 針對 Data JPA 的@DataJpaTest 、針 對 JDBC 的 @JdbcTest 針 對 MongoDB 的 @DataMongoTest 、 針 對 redis 的@DataRedisTest 等 。但 如 果 我 們 閱 讀 上 述 注 解 的 源 碼 , 會 發(fā) 現(xiàn) 其 處 理 機 制 與@AutoConfigureMockMvc 基 本一致 , 核 心 部分都使用了本章講到的@ImportAutoConfiguration 注解。
本章的重點并不僅僅是要教會大家如何使用單元測試,更重要的是傳達個思想:單元測試是保證代碼質(zhì)量的重要方式,在具體項目中,如果有可能,請盡量編寫單元測試代碼。

本文給大家講解的內(nèi)容是SpringBoot單元測試:MockMvc的自動配置
下篇文章給大家講解的是SpringBoot 打包部署解析;
覺得文章不錯的朋友可以轉(zhuǎn)發(fā)此文關(guān)注小編;
感謝大家的支持!
本文就是愿天堂沒有BUG給大家分享的內(nèi)容,大家有收獲的話可以分享下,想學(xué)習(xí)更多的話可以到微信公眾號里找我,我等你哦。
