日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

MockMVC

發(fā)布時(shí)間:2023/12/15 c/c++ 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MockMVC 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

隨著RESTful Web Service的流行,測試對外的Service是否滿足期望也變的必要的。從Spring 3.2開始Spring了Spring Web測試框架

?

Spring MVC測試框架提供了對服務(wù)器端和客戶端(基于RestTemplate的客戶端)提供了支持。

?

對于服務(wù)器端:在Spring 3.2之前,我們測試時(shí)一般都是直接new控制器,注入依賴,然后判斷返回值。但是我們無法連同Spring MVC的基礎(chǔ)設(shè)施(如DispatcherServlet調(diào)度、類型轉(zhuǎn)換、數(shù)據(jù)綁定、攔截器等)一起測試,另外也沒有現(xiàn)成的方法測試如最終渲染的視圖(@ResponseBody生成的JSON/XML、JSP、Velocity等)內(nèi)容是否正確。從Spring 3.2開始這些事情都可以完成了。而且可以測試完整的Spring MVC流程,即從URL請求到控制器處理,再到視圖渲染都可以測試。

?

對于客戶端:不需要啟動服務(wù)器即可測試我們的RESTful 服務(wù)。

1 服務(wù)器端測試

我的環(huán)境:JDK7、Maven3、spring4、Servlet3

?

首先添加依賴

如下是spring-context和spring-webmvc依賴:

Java代碼??
  • <dependency>??
  • ????<groupId>org.springframework</groupId>??
  • ????<artifactId>spring-context</artifactId>??
  • ????<version>${spring.version}</version>??
  • </dependency>??
  • ??
  • <dependency>??
  • ????<groupId>org.springframework</groupId>??
  • ????<artifactId>spring-webmvc</artifactId>??
  • ????<version>${spring.version}</version>??
  • </dependency>??
  • 版本信息:<spring.version>4.0.0.RELEASE</spring.version>

    ?

    如下是測試相關(guān)的依賴(junit、hamcrest、mockito、spring-test):

    Java代碼??
  • <dependency>??
  • ????<groupId>junit</groupId>??
  • ????<artifactId>junit</artifactId>??
  • ????<version>${junit.version}</version>??
  • ????<scope>test</scope>??
  • </dependency>??
  • ??
  • <dependency>??
  • ????<groupId>org.hamcrest</groupId>??
  • ????<artifactId>hamcrest-core</artifactId>??
  • ????<version>${hamcrest.core.version}/version>??
  • ????<scope>test</scope>??
  • </dependency>??
  • <dependency>??
  • ????<groupId>org.mockito</groupId>??
  • ????<artifactId>mockito-core</artifactId>??
  • ????<version>${mockito.core.version}</version>??
  • ????<scope>test</scope>??
  • </dependency>??
  • ??
  • <dependency>??
  • ????<groupId>org.springframework</groupId>??
  • ????<artifactId>spring-test</artifactId>??
  • ????<version>${spring.version}</version>??
  • ????<scope>test</scope>??
  • </dependency>??
  • 版本信息:<junit.version>4.11</junit.version>、<hamcrest.core.version>1.3</hamcrest.core.version>、<mockito.core.version>1.9.5</mockito.core.version>

    然后準(zhǔn)備測試相關(guān)配置

    實(shí)體:

    Java代碼??
  • package?com.sishuok.mvc.entity;??
  • import?java.io.Serializable;??
  • public?class?User?implements?Serializable?{??
  • ????private?Long?id;??
  • ????private?String?name;??
  • ????//省略getter/setter等??
  • }??
  • ?

    控制器:

    Java代碼??
  • package?com.sishuok.mvc.controller;??
  • //省略import??
  • @Controller??
  • @RequestMapping("/user")??
  • public?class?UserController?{??
  • ??
  • ????@RequestMapping("/{id}")??
  • ????public?ModelAndView?view(@PathVariable("id")?Long?id,?HttpServletRequest?req)?{??
  • ????????User?user?=?new?User();??
  • ????????user.setId(id);??
  • ????????user.setName("zhang");??
  • ??
  • ????????ModelAndView?mv?=?new?ModelAndView();??
  • ????????mv.addObject("user",?user);??
  • ????????mv.setViewName("user/view");??
  • ????????return?mv;??
  • ????}??
  • }??
  • ?

    XML風(fēng)格配置:

    spring-config.xml:加載非web層組件?

    Java代碼??
  • <?xml?version="1.0"?encoding="UTF-8"?>??
  • <beans?xmlns="http://www.springframework.org/schema/beans"??
  • ???????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"??
  • ???????xmlns:context="http://www.springframework.org/schema/context"??
  • ???????xsi:schemaLocation="??
  • ???????http://www.springframework.org/schema/beans?http://www.springframework.org/schema/beans/spring-beans.xsd??
  • ???????http://www.springframework.org/schema/context?http://www.springframework.org/schema/context/spring-context.xsd??
  • ???????">??
  • ????<!--?通過web.xml中的?org.springframework.web.context.ContextLoaderListener?加載的??-->??
  • ????<!--?請參考?http://jinnianshilongnian.iteye.com/blog/1602617??-->??
  • ????<context:component-scan?base-package="com.sishuok.mvc">??
  • ????????<context:exclude-filter?type="annotation"?expression="org.springframework.stereotype.Controller"/>??
  • ????</context:component-scan>??
  • </beans>??
  • ?

    spring-mvc.xml:加載和配置web層組件?

    Java代碼??
  • <?xml?version="1.0"?encoding="UTF-8"?>??
  • <beans?xmlns="http://www.springframework.org/schema/beans"??
  • ???????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"??
  • ???????xmlns:context="http://www.springframework.org/schema/context"??
  • ???????xmlns:mvc="http://www.springframework.org/schema/mvc"??
  • ???????xsi:schemaLocation="??
  • ???????http://www.springframework.org/schema/beans?http://www.springframework.org/schema/beans/spring-beans.xsd??
  • ???????http://www.springframework.org/schema/context?http://www.springframework.org/schema/context/spring-context.xsd??
  • ???????http://www.springframework.org/schema/mvc?http://www.springframework.org/schema/mvc/spring-mvc.xsd??
  • ???????">??
  • ????<!--?通過web.xml中的?org.springframework.web.servlet.DispatcherServlet?加載的??-->??
  • ????<!--?請參考?http://jinnianshilongnian.iteye.com/blog/1602617??-->??
  • ????<context:component-scan?base-package="com.sishuok.mvc"?use-default-filters="false">??
  • ????????<context:include-filter?type="annotation"?expression="org.springframework.stereotype.Controller"/>??
  • ????</context:component-scan>??
  • ????<mvc:annotation-driven/>??
  • ????<bean?id="viewResolver"?class="org.springframework.web.servlet.view.InternalResourceViewResolver">??
  • ????????<property?name="prefix"?value="/WEB-INF/jsp/"/>??
  • ????????<property?name="suffix"?value=".jsp"/>??
  • ????</bean>??
  • </beans> ?
  • web.xml配置

    ?

    [html]?view plaincopy
  • <?xml?version="1.0"?encoding="UTF-8"?>??
  • <web-app??
  • ????????xmlns="http://java.sun.com/xml/ns/javaee"??
  • ????????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"??
  • ????????xsi:schemaLocation="http://java.sun.com/xml/ns/javaee?http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"??
  • ????????version="3.0"??
  • ????????metadata-complete="false">??
  • ??
  • ????<!--?請禁用com.sishuok.config.WebInitializer后開啟如下配置?-->??
  • ??
  • ????<!--?Spring配置文件開始??-->??
  • ????<context-param>??
  • ????????<param-name>contextConfigLocation</param-name>??
  • ????????<param-value>??
  • ????????????classpath:spring-config.xml??
  • ????????</param-value>??
  • ????</context-param>??
  • ????<listener>??
  • ????????<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>??
  • ????</listener>??
  • ????<!--?Spring配置文件結(jié)束?-->??
  • ??
  • ????<!--?設(shè)置servlet編碼開始?-->??
  • ????<filter>??
  • ????????<filter-name>Set?Character?Encoding</filter-name>??
  • ????????<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>??
  • ????????<async-supported>true</async-supported>??
  • ????????<init-param>??
  • ????????????<param-name>encoding</param-name>??
  • ????????????<param-value>UTF-8</param-value>??
  • ????????</init-param>??
  • ????????<init-param>??
  • ????????????<param-name>forceEncoding</param-name>??
  • ????????????<param-value>true</param-value>??
  • ????????</init-param>??
  • ????</filter>??
  • ????<filter-mapping>??
  • ????????<filter-name>Set?Character?Encoding</filter-name>??
  • ????????<url-pattern>/*</url-pattern>??
  • ????</filter-mapping>??
  • ????<!--?設(shè)置servlet編碼結(jié)束?-->??
  • ??
  • ????<servlet>??
  • ????????<servlet-name>spring</servlet-name>??
  • ????????<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>??
  • ????????<init-param>??
  • ????????????<param-name>contextConfigLocation</param-name>??
  • ????????????<param-value>classpath:spring-mvc.xml</param-value>??
  • ????????</init-param>??
  • ????????<load-on-startup>1</load-on-startup>??
  • ????????<async-supported>true</async-supported>??
  • ????</servlet>??
  • ????<servlet-mapping>??
  • ????????<servlet-name>spring</servlet-name>??
  • ????????<url-pattern>/</url-pattern>??
  • ????</servlet-mapping>??
  • ??
  • ??
  • </web-app>??
  • ?

    等價(jià)的注解風(fēng)格配置:?

    AppConfig.java:等價(jià)于spring-config.xml

    Java代碼??
  • package?com.sishuok.config;??
  • ??
  • import?org.springframework.context.annotation.ComponentScan;??
  • import?org.springframework.context.annotation.Configuration;??
  • import?org.springframework.context.annotation.FilterType;??
  • import?org.springframework.stereotype.Controller;??
  • ??
  • @Configuration??
  • @ComponentScan(basePackages?=?"com.sishuok.mvc",?excludeFilters?=?{??
  • ????????@ComponentScan.Filter(type?=?FilterType.ANNOTATION,?value?=?{Controller.class})??
  • })??
  • public?class?AppConfig?{??
  • }??
  • ?

    MvcConfig.java:等價(jià)于spring-mvc.xml

    Java代碼??
  • package?com.sishuok.config;??
  • ??
  • import?org.springframework.context.annotation.Bean;??
  • import?org.springframework.context.annotation.ComponentScan;??
  • import?org.springframework.context.annotation.Configuration;??
  • import?org.springframework.context.annotation.FilterType;??
  • import?org.springframework.stereotype.Controller;??
  • import?org.springframework.web.servlet.ViewResolver;??
  • import?org.springframework.web.servlet.config.annotation.EnableWebMvc;??
  • import?org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;??
  • import?org.springframework.web.servlet.view.InternalResourceViewResolver;??
  • ??
  • @Configuration??
  • @EnableWebMvc??
  • @ComponentScan(basePackages?=?"com.sishuok.mvc",?useDefaultFilters?=?false,?includeFilters?=?{??
  • ????????@ComponentScan.Filter(type?=?FilterType.ANNOTATION,?value?=?{Controller.class})??
  • })??
  • public?class?MvcConfig?extends?WebMvcConfigurationSupport?{??
  • ??
  • ????@Bean??
  • ????public?ViewResolver?viewResolver()?{??
  • ????????InternalResourceViewResolver?viewResolver?=?new?InternalResourceViewResolver();??
  • ????????viewResolver.setPrefix("/WEB-INF/jsp/");??
  • ????????viewResolver.setSuffix(".jsp");??
  • ????????return?viewResolver;??
  • ????}??
  • ??
  • }??

  • WebInitializer.java:注冊相應(yīng)的web.xml中的組件

    Java代碼??
  • package?com.sishuok.config;??
  • ??
  • import?org.springframework.web.WebApplicationInitializer;??
  • import?org.springframework.web.context.ContextLoaderListener;??
  • import?org.springframework.web.context.support.AnnotationConfigWebApplicationContext;??
  • import?org.springframework.web.filter.CharacterEncodingFilter;??
  • import?org.springframework.web.servlet.DispatcherServlet;??
  • ??
  • import?javax.servlet.DispatcherType;??
  • import?javax.servlet.FilterRegistration;??
  • import?javax.servlet.ServletException;??
  • import?javax.servlet.ServletRegistration;??
  • import?java.util.EnumSet;??
  • ??
  • public?class?WebInitializer?implements?WebApplicationInitializer?{??
  • ??
  • ????@Override??
  • ????public?void?onStartup(javax.servlet.ServletContext?sc)?throws?ServletException?{??
  • ??
  • ????????AnnotationConfigWebApplicationContext?rootContext?=?new?AnnotationConfigWebApplicationContext();??
  • ????????rootContext.register(AppConfig.class);??
  • ????????sc.addListener(new?ContextLoaderListener(rootContext));??
  • ??
  • ????????//2、springmvc上下文??
  • ????????AnnotationConfigWebApplicationContext?springMvcContext?=?new?AnnotationConfigWebApplicationContext();??
  • ????????springMvcContext.register(MvcConfig.class);??
  • ????????//3、DispatcherServlet??
  • ????????DispatcherServlet?dispatcherServlet?=?new?DispatcherServlet(springMvcContext);??
  • ????????ServletRegistration.Dynamic?dynamic?=?sc.addServlet("dispatcherServlet",?dispatcherServlet);??
  • ????????dynamic.setLoadOnStartup(1);??
  • ????????dynamic.addMapping("/");??
  • ??
  • ????????//4、CharacterEncodingFilter??
  • ????????CharacterEncodingFilter?characterEncodingFilter?=?new?CharacterEncodingFilter();??
  • ????????characterEncodingFilter.setEncoding("utf-8");??
  • ????????FilterRegistration?filterRegistration?=??
  • ????????????????sc.addFilter("characterEncodingFilter",?characterEncodingFilter);??
  • ????????filterRegistration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST),?false,?"/");??
  • ??
  • ????}??
  • }??
  • ?

    到此基本的配置就搞定了,接下來看看如何測試吧。?

    1.1 安裝測試環(huán)境

    spring mvc測試框架提供了兩種方式,獨(dú)立安裝和集成Web環(huán)境測試(此種方式并不會集成真正的web環(huán)境,而是通過相應(yīng)的Mock API進(jìn)行模擬測試,無須啟動服務(wù)器)。

    ?

    獨(dú)立測試方式

    Java代碼??
  • public?class?UserControllerStandaloneSetupTest?{??
  • ????private?MockMvc?mockMvc;??
  • ????@Before??
  • ????public?void?setUp()?{??
  • ????????UserController?userController?=?new?UserController();??
  • ????????mockMvc?=?MockMvcBuilders.standaloneSetup(userController).build();??
  • ????}??
  • }??
  • 1、首先自己創(chuàng)建相應(yīng)的控制器,注入相應(yīng)的依賴

    2、通過MockMvcBuilders.standaloneSetup模擬一個(gè)Mvc測試環(huán)境,通過build得到一個(gè)MockMvc

    3、MockMvc:是我們以后測試時(shí)經(jīng)常使用的API,后邊介紹

    ?

    集成Web環(huán)境方式

    Java代碼??
  • //XML風(fēng)格??
  • @RunWith(SpringJUnit4ClassRunner.class)??
  • @WebAppConfiguration(value?=?"src/main/webapp")??
  • @ContextHierarchy({??
  • ????????@ContextConfiguration(name?=?"parent",?locations?=?"classpath:spring-config.xml"),??
  • ????????@ContextConfiguration(name?=?"child",?locations?=?"classpath:spring-mvc.xml")??
  • })??
  • ??
  • //注解風(fēng)格??
  • //@RunWith(SpringJUnit4ClassRunner.class)??
  • //@WebAppConfiguration(value?=?"src/main/webapp")??
  • //@ContextHierarchy({??
  • //????????@ContextConfiguration(name?=?"parent",?classes?=?AppConfig.class),??
  • //????????@ContextConfiguration(name?=?"child",?classes?=?MvcConfig.class)??
  • //})??
  • public?class?UserControllerWebAppContextSetupTest?{??
  • ??
  • ????@Autowired??
  • ????private?WebApplicationContext?wac;??
  • ????private?MockMvc?mockMvc;??
  • ??
  • ????@Before??
  • ????public?void?setUp()?{??
  • ????????mockMvc?=?MockMvcBuilders.webAppContextSetup(wac).build();??
  • ????}??
  • }??
  • 1、@WebAppConfiguration:測試環(huán)境使用,用來表示測試環(huán)境使用的ApplicationContext將是WebApplicationContext類型的;value指定web應(yīng)用的根;

    2、@ContextHierarchy:指定容器層次,即spring-config.xml是父容器,而spring-mvc.xml是子容器

    3、通過@Autowired?WebApplicationContext wac:注入web環(huán)境的ApplicationContext容器;

    4、然后通過MockMvcBuilders.webAppContextSetup(wac).build()創(chuàng)建一個(gè)MockMvc進(jìn)行測試;

    ?

    到此測試環(huán)境就搭建完成了,根據(jù)需要選擇使用哪種方式即可。

    ?

    1.2、HelloWorld

    Java代碼??
  • @Test??
  • public?void?testView()?throws?Exception?{??
  • ????MvcResult?result?=?mockMvc.perform(MockMvcRequestBuilders.get("/user/1"))??
  • ????????????.andExpect(MockMvcResultMatchers.view().name("user/view"))??
  • ????????????.andExpect(MockMvcResultMatchers.model().attributeExists("user"))??
  • ????????????.andDo(MockMvcResultHandlers.print())??
  • ????????????.andReturn();??
  • ??????
  • ????Assert.assertNotNull(result.getModelAndView().getModel().get("user"));??
  • }??
  • 1、mockMvc.perform執(zhí)行一個(gè)請求;

    2、MockMvcRequestBuilders.get("/user/1")構(gòu)造一個(gè)請求

    3、ResultActions.andExpect添加執(zhí)行完成后的斷言

    4、ResultActions.andDo添加一個(gè)結(jié)果處理器,表示要對結(jié)果做點(diǎn)什么事情,比如此處使用MockMvcResultHandlers.print()輸出整個(gè)響應(yīng)結(jié)果信息。

    5、ResultActions.andReturn表示執(zhí)行完成后返回相應(yīng)的結(jié)果。

    ?

    整個(gè)測試過程非常有規(guī)律:

    1、準(zhǔn)備測試環(huán)境

    2、通過MockMvc執(zhí)行請求

    3.1、添加驗(yàn)證斷言

    3.2、添加結(jié)果處理器

    3.3、得到MvcResult進(jìn)行自定義斷言/進(jìn)行下一步的異步請求

    4、卸載測試環(huán)境

    ?

    ?

    1.4、了解測試API

    Spring mvc測試框架提供了測試MVC需要的API,主要包括Servlet/JSP Mock、MockMvcBuilder、MockMvc、RequestBuilder、ResultMatcher、ResultHandler、MvcResult等。另外提供了幾個(gè)靜態(tài)工廠方法便于測試:MockMvcBuilders、MockMvcRequestBuilders、MockMvcResultMatchers、MockMvcResultHandlers。在使用時(shí)請使用靜態(tài)方法導(dǎo)入方便測試,如:

    Java代碼??
  • import?static?org.springframework.test.web.servlet.setup.MockMvcBuilders.*;??
  • import?static?org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;??
  • import?static?org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;??
  • import?static?org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;??
  • ?

    Servlet/JSP API Mock?

    提供了對Servlet 3 相應(yīng)API的Mock,如:

    MockServletContext

    MockHttpServletRequest

    MockHttpServletResponse

    ……

    具體請查看spring-test模塊的org.springframework.mock.web包。

    ?

    ?

    MockMvcBuilder/MockMvcBuilders

    MockMvcBuilder是用來構(gòu)造MockMvc的構(gòu)造器,其主要有兩個(gè)實(shí)現(xiàn):StandaloneMockMvcBuilder和DefaultMockMvcBuilder,分別對應(yīng)之前的兩種測試方式。對于我們來說直接使用靜態(tài)工廠MockMvcBuilders創(chuàng)建即可:

    MockMvcBuilders.webAppContextSetup(WebApplicationContext context):指定WebApplicationContext,將會從該上下文獲取相應(yīng)的控制器并得到相應(yīng)的MockMvc;

    MockMvcBuilders.standaloneSetup(Object... controllers):通過參數(shù)指定一組控制器,這樣就不需要從上下文獲取了;

    ?

    其中DefaultMockMvcBuilder還提供了如下API:

    addFilters(Filter... filters)/addFilter(Filter filter, String... urlPatterns):添加javax.servlet.Filter過濾器

    defaultRequest(RequestBuilder requestBuilder):默認(rèn)的RequestBuilder,每次執(zhí)行時(shí)會合并到自定義的RequestBuilder中,即提供公共請求數(shù)據(jù)的;

    alwaysExpect(ResultMatcher resultMatcher):定義全局的結(jié)果驗(yàn)證器,即每次執(zhí)行請求時(shí)都進(jìn)行驗(yàn)證的規(guī)則;

    alwaysDo(ResultHandler resultHandler):定義全局結(jié)果處理器,即每次請求時(shí)都進(jìn)行結(jié)果處理;

    dispatchOptions:DispatcherServlet是否分發(fā)OPTIONS請求方法到控制器;

    ?

    StandaloneMockMvcBuilder繼承了DefaultMockMvcBuilder,又提供了如下API:

    setMessageConverters(HttpMessageConverter<?>...messageConverters):設(shè)置HTTP消息轉(zhuǎn)換器;

    setValidator(Validator validator):設(shè)置驗(yàn)證器;

    setConversionService(FormattingConversionService conversionService):設(shè)置轉(zhuǎn)換服務(wù);

    addInterceptors(HandlerInterceptor... interceptors)/addMappedInterceptors(String[] pathPatterns, HandlerInterceptor... interceptors):添加spring mvc攔截器;

    setContentNegotiationManager(ContentNegotiationManager contentNegotiationManager):設(shè)置內(nèi)容協(xié)商管理器;

    setAsyncRequestTimeout(long timeout):設(shè)置異步超時(shí)時(shí)間;

    setCustomArgumentResolvers(HandlerMethodArgumentResolver... argumentResolvers):設(shè)置自定義控制器方法參數(shù)解析器;

    setCustomReturnValueHandlers(HandlerMethodReturnValueHandler... handlers):設(shè)置自定義控制器方法返回值處理器;

    setHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers)/setHandlerExceptionResolvers(HandlerExceptionResolver... exceptionResolvers):設(shè)置異常解析器;

    setViewResolvers(ViewResolver...resolvers):設(shè)置視圖解析器;

    setSingleView(View view):設(shè)置單個(gè)視圖,即視圖解析時(shí)總是解析到這一個(gè)(僅適用于只有一個(gè)視圖的情況);

    setLocaleResolver(LocaleResolver localeResolver):設(shè)置Local解析器;

    setFlashMapManager(FlashMapManager flashMapManager):設(shè)置FlashMapManager,如存儲重定向數(shù)據(jù);

    setUseSuffixPatternMatch(boolean useSuffixPatternMatch):設(shè)置是否是后綴模式匹配,如“/user”是否匹配"/user.*",默認(rèn)真即匹配;

    setUseTrailingSlashPatternMatch(boolean useTrailingSlashPatternMatch):設(shè)置是否自動后綴路徑模式匹配,如“/user”是否匹配“/user/”,默認(rèn)真即匹配;

    addPlaceHolderValue(String name, String value) :添加request mapping中的占位符替代;

    ?

    因?yàn)镾tandaloneMockMvcBuilder不會加載Spring MVC配置文件,因此就不會注冊我們需要的一些組件,因此就提供了如上API用于注冊我們需要的相應(yīng)組件。

    ?

    MockMvc

    使用之前的MockMvcBuilder.build()得到構(gòu)建好的MockMvc;這個(gè)是mvc測試的核心API,對于該API的使用方式如下:

    Java代碼??
  • MvcResult?result?=?mockMvc.perform(MockMvcRequestBuilders.get("/user/1"))??
  • ???????.andExpect(MockMvcResultMatchers.view().name("user/view"))??
  • ???????.andExpect(MockMvcResultMatchers.model().attributeExists("user"))??
  • ???????.andDo(MockMvcResultHandlers.print())??
  • ???????.andReturn();??
  • perform:執(zhí)行一個(gè)RequestBuilder請求,會自動執(zhí)行SpringMVC的流程并映射到相應(yīng)的控制器執(zhí)行處理;

    andExpect:添加ResultMatcher驗(yàn)證規(guī)則,驗(yàn)證控制器執(zhí)行完成后結(jié)果是否正確;

    andDo:添加ResultHandler結(jié)果處理器,比如調(diào)試時(shí)打印結(jié)果到控制臺;

    andReturn:最后返回相應(yīng)的MvcResult;然后進(jìn)行自定義驗(yàn)證/進(jìn)行下一步的異步處理;

    ?

    另外還提供了以下API:

    setDefaultRequest:設(shè)置默認(rèn)的RequestBuilder,用于在每次perform執(zhí)行相應(yīng)的RequestBuilder時(shí)自動把該默認(rèn)的RequestBuilder合并到perform的RequestBuilder中;

    setGlobalResultMatchers:設(shè)置全局的預(yù)期結(jié)果驗(yàn)證規(guī)則,如我們通過MockMvc測試多個(gè)控制器時(shí),假設(shè)它們都想驗(yàn)證某個(gè)規(guī)則時(shí),就可以使用這個(gè);

    setGlobalResultHandlers:設(shè)置全局的ResultHandler結(jié)果處理器;

    ??

    RequestBuilder/MockMvcRequestBuilders

    從名字可以看出,RequestBuilder用來構(gòu)建請求的,其提供了一個(gè)方法buildRequest(ServletContext servletContext)用于構(gòu)建MockHttpServletRequest;其主要有兩個(gè)子類MockHttpServletRequestBuilder和MockMultipartHttpServletRequestBuilder(如文件上傳使用),即用來Mock客戶端請求需要的所有數(shù)據(jù)。

    ?

    MockMvcRequestBuilders主要API:

    MockHttpServletRequestBuilder get(String urlTemplate, Object... urlVariables):根據(jù)uri模板和uri變量值得到一個(gè)GET請求方式的MockHttpServletRequestBuilder;如get("/user/{id}", 1L);

    MockHttpServletRequestBuilder post(String urlTemplate, Object... urlVariables):同get類似,但是是POST方法;

    MockHttpServletRequestBuilder put(String urlTemplate, Object... urlVariables):同get類似,但是是PUT方法;

    MockHttpServletRequestBuilder delete(String urlTemplate, Object... urlVariables) :同get類似,但是是DELETE方法;

    MockHttpServletRequestBuilder options(String urlTemplate, Object... urlVariables):同get類似,但是是OPTIONS方法;

    MockHttpServletRequestBuilder request(HttpMethod httpMethod, String urlTemplate, Object... urlVariables):提供自己的Http請求方法及uri模板和uri變量,如上API都是委托給這個(gè)API;

    MockMultipartHttpServletRequestBuilder fileUpload(String urlTemplate, Object... urlVariables):提供文件上傳方式的請求,得到MockMultipartHttpServletRequestBuilder;

    RequestBuilder asyncDispatch(final MvcResult mvcResult):創(chuàng)建一個(gè)從啟動異步處理的請求的MvcResult進(jìn)行異步分派的RequestBuilder;

    ?

    接下來再看看MockHttpServletRequestBuilder和MockMultipartHttpServletRequestBuilder API:

    MockHttpServletRequestBuilder API:

    MockHttpServletRequestBuilder header(String name, Object... values)/MockHttpServletRequestBuilder headers(HttpHeaders httpHeaders):添加頭信息;

    MockHttpServletRequestBuilder contentType(MediaType mediaType):指定請求的contentType頭信息;

    MockHttpServletRequestBuilder accept(MediaType... mediaTypes)/MockHttpServletRequestBuilder accept(String... mediaTypes):指定請求的Accept頭信息;

    MockHttpServletRequestBuilder content(byte[] content)/MockHttpServletRequestBuilder content(String content):指定請求Body體內(nèi)容;

    MockHttpServletRequestBuilder cookie(Cookie... cookies):指定請求的Cookie;

    MockHttpServletRequestBuilder locale(Locale locale):指定請求的Locale;

    MockHttpServletRequestBuilder characterEncoding(String encoding):指定請求字符編碼;

    MockHttpServletRequestBuilder requestAttr(String name, Object value) :設(shè)置請求屬性數(shù)據(jù);

    MockHttpServletRequestBuilder sessionAttr(String name, Object value)/MockHttpServletRequestBuilder sessionAttrs(Map<String, Object> sessionAttributes):設(shè)置請求session屬性數(shù)據(jù);

    MockHttpServletRequestBuilder flashAttr(String name, Object value)/MockHttpServletRequestBuilder flashAttrs(Map<String, Object> flashAttributes):指定請求的flash信息,比如重定向后的屬性信息;

    MockHttpServletRequestBuilder session(MockHttpSession session) :指定請求的Session;

    MockHttpServletRequestBuilder principal(Principal principal) :指定請求的Principal;

    MockHttpServletRequestBuilder contextPath(String contextPath) :指定請求的上下文路徑,必須以“/”開頭,且不能以“/”結(jié)尾;

    MockHttpServletRequestBuilder pathInfo(String pathInfo) :請求的路徑信息,必須以“/”開頭;

    MockHttpServletRequestBuilder secure(boolean secure):請求是否使用安全通道;

    MockHttpServletRequestBuilder with(RequestPostProcessor postProcessor):請求的后處理器,用于自定義一些請求處理的擴(kuò)展點(diǎn);

    ?

    MockMultipartHttpServletRequestBuilder繼承自MockHttpServletRequestBuilder,又提供了如下API:

    MockMultipartHttpServletRequestBuilder file(String name, byte[] content)/MockMultipartHttpServletRequestBuilder file(MockMultipartFile file):指定要上傳的文件;

    ?

    ResultActions

    調(diào)用MockMvc.perform(RequestBuilder requestBuilder)后將得到ResultActions,通過ResultActions完成如下三件事:

    ResultActions andExpect(ResultMatcher matcher) :添加驗(yàn)證斷言來判斷執(zhí)行請求后的結(jié)果是否是預(yù)期的;

    ResultActions andDo(ResultHandler handler) :添加結(jié)果處理器,用于對驗(yàn)證成功后執(zhí)行的動作,如輸出下請求/結(jié)果信息用于調(diào)試;

    MvcResult andReturn() :返回驗(yàn)證成功后的MvcResult;用于自定義驗(yàn)證/下一步的異步處理;

    ?

    ResultMatcher/MockMvcResultMatchers

    ResultMatcher用來匹配執(zhí)行完請求后的結(jié)果驗(yàn)證,其就一個(gè)match(MvcResult result)斷言方法,如果匹配失敗將拋出相應(yīng)的異常;spring mvc測試框架提供了很多***ResultMatchers來滿足測試需求。注意這些***ResultMatchers并不是ResultMatcher的子類,而是返回ResultMatcher實(shí)例的。Spring mvc測試框架為了測試方便提供了MockMvcResultMatchers靜態(tài)工廠方法方便操作;具體的API如下:

    HandlerResultMatchers handler():請求的Handler驗(yàn)證器,比如驗(yàn)證處理器類型/方法名;此處的Handler其實(shí)就是處理請求的控制器;

    RequestResultMatchers request():得到RequestResultMatchers驗(yàn)證器;

    ModelResultMatchers model():得到模型驗(yàn)證器;

    ViewResultMatchers view():得到視圖驗(yàn)證器;

    FlashAttributeResultMatchers flash():得到Flash屬性驗(yàn)證;

    StatusResultMatchers status():得到響應(yīng)狀態(tài)驗(yàn)證器;

    HeaderResultMatchers header():得到響應(yīng)Header驗(yàn)證器;

    CookieResultMatchers cookie():得到響應(yīng)Cookie驗(yàn)證器;

    ContentResultMatchers content():得到響應(yīng)內(nèi)容驗(yàn)證器;

    JsonPathResultMatchers jsonPath(String expression, Object ... args)/ResultMatcher jsonPath(String expression, Matcher<T> matcher):得到Json表達(dá)式驗(yàn)證器;

    XpathResultMatchers xpath(String expression, Object... args)/XpathResultMatchers xpath(String expression, Map<String, String> namespaces, Object... args):得到Xpath表達(dá)式驗(yàn)證器;

    ResultMatcher forwardedUrl(final String expectedUrl):驗(yàn)證處理完請求后轉(zhuǎn)發(fā)的url(絕對匹配);

    ResultMatcher forwardedUrlPattern(final String urlPattern):驗(yàn)證處理完請求后轉(zhuǎn)發(fā)的url(Ant風(fēng)格模式匹配,@since spring4);

    ResultMatcher redirectedUrl(final String expectedUrl):驗(yàn)證處理完請求后重定向的url(絕對匹配);

    ResultMatcher redirectedUrlPattern(final String expectedUrl):驗(yàn)證處理完請求后重定向的url(Ant風(fēng)格模式匹配,@since spring4);

    ?

    得到相應(yīng)的***ResultMatchers后,接著再調(diào)用其相應(yīng)的API得到ResultMatcher,如ModelResultMatchers.attributeExists(final String... names)判斷Model屬性是否存在。具體請查看相應(yīng)的API。再次就不一一列舉了。

    ?

    ?

    ResultHandler/MockMvcResultHandlers

    ResultHandler用于對處理的結(jié)果進(jìn)行相應(yīng)處理的,比如輸出整個(gè)請求/響應(yīng)等信息方便調(diào)試,Spring mvc測試框架提供了MockMvcResultHandlers靜態(tài)工廠方法,該工廠提供了ResultHandler print()返回一個(gè)輸出MvcResult詳細(xì)信息到控制臺的ResultHandler實(shí)現(xiàn)。

    ?

    ?

    MvcResult

    即執(zhí)行完控制器后得到的整個(gè)結(jié)果,并不僅僅是返回值,其包含了測試時(shí)需要的所有信息,如:

    MockHttpServletRequest getRequest():得到執(zhí)行的請求;

    MockHttpServletResponse getResponse():得到執(zhí)行后的響應(yīng);

    Object getHandler():得到執(zhí)行的處理器,一般就是控制器;

    HandlerInterceptor[] getInterceptors():得到對處理器進(jìn)行攔截的攔截器;

    ModelAndView getModelAndView():得到執(zhí)行后的ModelAndView;

    Exception getResolvedException():得到HandlerExceptionResolver解析后的異常;

    FlashMap getFlashMap():得到FlashMap;

    Object getAsyncResult()/Object getAsyncResult(long timeout):得到異步執(zhí)行的結(jié)果;

    ?

    1.5 測試示例

    測試普通控制器?

    Java代碼??
  • //測試普通控制器??
  • mockMvc.perform(get("/user/{id}",?1))?//執(zhí)行請求??
  • ????????.andExpect(model().attributeExists("user"))?//驗(yàn)證存儲模型數(shù)據(jù)??
  • ????????.andExpect(view().name("user/view"))?//驗(yàn)證viewName??
  • ????????.andExpect(forwardedUrl("/WEB-INF/jsp/user/view.jsp"))//驗(yàn)證視圖渲染時(shí)forward到的jsp??
  • ????????.andExpect(status().isOk())//驗(yàn)證狀態(tài)碼??
  • ????????.andDo(print());?//輸出MvcResult到控制臺??
  • ?

    測試普通控制器,但是URL錯(cuò)誤,即404

    Java代碼??
  • //找不到控制器,404測試??
  • MvcResult?result?=?mockMvc.perform(get("/user2/{id}",?1))?//執(zhí)行請求??
  • ????????.andDo(print())??
  • ????????.andExpect(status().isNotFound())?//驗(yàn)證控制器不存在??
  • ????????.andReturn();??
  • Assert.assertNull(result.getModelAndView());?//自定義斷言??
  • ?

    得到MvcResult自定義驗(yàn)證 ???

    Java代碼??
  • MvcResult?result?=?mockMvc.perform(get("/user/{id}",?1))//執(zhí)行請求??
  • ????????.andReturn();?//返回MvcResult??
  • Assert.assertNotNull(result.getModelAndView().getModel().get("user"));?//自定義斷言??
  • ?

    驗(yàn)證請求參數(shù)綁定到模型數(shù)據(jù)及Flash屬性?

    Java代碼??
  • mockMvc.perform(post("/user").param("name",?"zhang"))?//執(zhí)行傳遞參數(shù)的POST請求(也可以post("/user?name=zhang"))??
  • ????????.andExpect(handler().handlerType(UserController.class))?//驗(yàn)證執(zhí)行的控制器類型??
  • ????????.andExpect(handler().methodName("create"))?//驗(yàn)證執(zhí)行的控制器方法名??
  • ????????.andExpect(model().hasNoErrors())?//驗(yàn)證頁面沒有錯(cuò)誤??
  • ????????.andExpect(flash().attributeExists("success"))?//驗(yàn)證存在flash屬性??
  • ????????.andExpect(view().name("redirect:/user"));?//驗(yàn)證視圖??
  • ?

    驗(yàn)證請求參數(shù)驗(yàn)證失敗出錯(cuò)??

    Java代碼??
  • mockMvc.perform(post("/user").param("name",?"admin"))?//執(zhí)行請求??
  • ????????.andExpect(model().hasErrors())?//驗(yàn)證模型有錯(cuò)誤??
  • ????????.andExpect(model().attributeDoesNotExist("name"))?//驗(yàn)證存在錯(cuò)誤的屬性??
  • ????????.andExpect(view().name("showCreateForm"));?//驗(yàn)證視圖??
  • ?

    文件上傳?

    Java代碼??
  • //文件上傳??
  • byte[]?bytes?=?new?byte[]?{1,?2};??
  • mockMvc.perform(fileUpload("/user/{id}/icon",?1L).file("icon",?bytes))?//執(zhí)行文件上傳??
  • ????????.andExpect(model().attribute("icon",?bytes))?//驗(yàn)證屬性相等性??
  • ????????.andExpect(view().name("success"));?//驗(yàn)證視圖??
  • ?

    JSON請求/響應(yīng)驗(yàn)證

    測試時(shí)需要安裝jackson Json和JsonPath依賴:?

    Java代碼??
  • <dependency>??
  • ????<groupId>com.fasterxml.jackson.core</groupId>??
  • ????<artifactId>jackson-databind</artifactId>??
  • ????<version>${jackson2.version}</version>??
  • </dependency>??
  • ??
  • <dependency>??
  • ????<groupId>com.jayway.jsonpath</groupId>??
  • ????<artifactId>json-path</artifactId>??
  • ????<version>${jsonpath.version}</version>??
  • ????<scope>test</scope>??
  • </dependency>??
  • 版本:<jsonpath.version>0.9.0</jsonpath.version>、<jackson2.version>2.2.3</jackson2.version>? Java代碼??
  • String?requestBody?=?"{\"id\":1,?\"name\":\"zhang\"}";??
  • mockMvc.perform(post("/user")??
  • ????????????.contentType(MediaType.APPLICATION_JSON).content(requestBody)??
  • ????????????.accept(MediaType.APPLICATION_JSON))?//執(zhí)行請求??
  • ????????.andExpect(content().contentType(MediaType.APPLICATION_JSON))?//驗(yàn)證響應(yīng)contentType??
  • ????????.andExpect(jsonPath("$.id").value(1));?//使用Json?path驗(yàn)證JSON?請參考http://goessner.net/articles/JsonPath/??
  • ??
  • String?errorBody?=?"{id:1,?name:zhang}";??
  • MvcResult?result?=?mockMvc.perform(post("/user")??
  • ????????.contentType(MediaType.APPLICATION_JSON).content(errorBody)??
  • ????????.accept(MediaType.APPLICATION_JSON))?//執(zhí)行請求??
  • ????????.andExpect(status().isBadRequest())?//400錯(cuò)誤請求??
  • ????????.andReturn();??
  • ??
  • Assert.assertTrue(HttpMessageNotReadableException.class.isAssignableFrom(result.getResolvedException().getClass()));//錯(cuò)誤的請求內(nèi)容體??
  • ?

    XML請求/響應(yīng)驗(yàn)證

    測試時(shí)需要安裝spring oxm和xstream依賴:?

    Java代碼??
  • <dependency>??
  • ????<groupId>com.thoughtworks.xstream</groupId>??
  • ????<artifactId>xstream</artifactId>??
  • ????<version>${xsream.version}</version>??
  • ????<scope>test</scope>??
  • </dependency>??
  • ??
  • <dependency>??
  • ????<groupId>org.springframework</groupId>??
  • ????<artifactId>spring-oxm</artifactId>??
  • ????<version>${spring.version}</version>??
  • ????<scope>test</scope>??
  • </dependency>??
  • 版本:<xstream.version>1.4.4</xstream.version> Java代碼??
  • //XML請求/響應(yīng)??
  • String?requestBody?=?"<user><id>1</id><name>zhang</name></user>";??
  • mockMvc.perform(post("/user")??
  • ????????.contentType(MediaType.APPLICATION_XML).content(requestBody)??
  • ????????.accept(MediaType.APPLICATION_XML))?//執(zhí)行請求??
  • ????????.andDo(print())??
  • ????????.andExpect(content().contentType(MediaType.APPLICATION_XML))?//驗(yàn)證響應(yīng)contentType??
  • ????????.andExpect(xpath("/user/id/text()").string("1"));?//使用XPath表達(dá)式驗(yàn)證XML?請參考http://www.w3school.com.cn/xpath/??
  • ??
  • String?errorBody?=?"<user><id>1</id><name>zhang</name>";??
  • MvcResult?result?=?mockMvc.perform(post("/user")??
  • ????????.contentType(MediaType.APPLICATION_XML).content(errorBody)??
  • ????????.accept(MediaType.APPLICATION_XML))?//執(zhí)行請求??
  • ????????.andExpect(status().isBadRequest())?//400錯(cuò)誤請求??
  • ????????.andReturn();??
  • ??
  • Assert.assertTrue(HttpMessageNotReadableException.class.isAssignableFrom(result.getResolvedException().getClass()));//錯(cuò)誤的請求內(nèi)容體??
  • ?

    異常處理??

    Java代碼??
  • //異常處理??
  • MvcResult?result?=?mockMvc.perform(get("/user/exception"))?//執(zhí)行請求??
  • ????????.andExpect(status().isInternalServerError())?//驗(yàn)證服務(wù)器內(nèi)部錯(cuò)誤??
  • ????????.andReturn();??
  • ??
  • Assert.assertTrue(IllegalArgumentException.class.isAssignableFrom(result.getResolvedException().getClass()));??
  • ?

    靜態(tài)資源?

    Java代碼??
  • //靜態(tài)資源??
  • mockMvc.perform(get("/static/app.js"))?//執(zhí)行請求??
  • ????????.andExpect(status().isOk())?//驗(yàn)證狀態(tài)碼200??
  • ????????.andExpect(content().string(CoreMatchers.containsString("var")));//驗(yàn)證渲染后的視圖內(nèi)容包含var??
  • ??
  • mockMvc.perform(get("/static/app1.js"))?//執(zhí)行請求??
  • ????????.andExpect(status().isNotFound());??//驗(yàn)證狀態(tài)碼404??
  • 異步測試?

    Java代碼??
  • //Callable??
  • MvcResult?result?=?mockMvc.perform(get("/user/async1?id=1&name=zhang"))?//執(zhí)行請求??
  • ????????.andExpect(request().asyncStarted())??
  • ????????.andExpect(request().asyncResult(CoreMatchers.instanceOf(User.class)))?//默認(rèn)會等10秒超時(shí)??
  • ????????.andReturn();??
  • ??
  • mockMvc.perform(asyncDispatch(result))??
  • ????????.andExpect(status().isOk())??
  • ????????.andExpect(content().contentType(MediaType.APPLICATION_JSON))??
  • ????????.andExpect(jsonPath("$.id").value(1));??
  • Java代碼??
  • //DeferredResult??
  • result?=?mockMvc.perform(get("/user/async2?id=1&name=zhang"))?//執(zhí)行請求??
  • ????????.andExpect(request().asyncStarted())??
  • ????????.andExpect(request().asyncResult(CoreMatchers.instanceOf(User.class)))??//默認(rèn)會等10秒超時(shí)??
  • ????????.andReturn();??
  • ??
  • mockMvc.perform(asyncDispatch(result))??
  • ????????.andExpect(status().isOk())??
  • ????????.andExpect(content().contentType(MediaType.APPLICATION_JSON))??
  • ????????.andExpect(jsonPath("$.id").value(1));??
  • 此處請?jiān)诘谝淮握埱髸r(shí)加上 andExpect(request().asyncResult(CoreMatchers.instanceOf(User.class)))這樣會等待結(jié)果返回/超時(shí),無須自己設(shè)置線程等待了;此處注意request().asyncResult一定是在第一次請求發(fā)出;然后第二次通過asyncDispatch進(jìn)行異步請求。

    ?

    添加自定義過濾器

    Java代碼??
  • mockMvc?=?webAppContextSetup(wac).addFilter(new?MyFilter(),?"/*").build();??
  • mockMvc.perform(get("/user/1"))??
  • ????????.andExpect(request().attribute("filter",?true));??
  • ?

    全局配置?

    Java代碼??
  • mockMvc?=?webAppContextSetup(wac)??
  • ????????.defaultRequest(get("/user/1").requestAttr("default",?true))?//默認(rèn)請求?如果其是Mergeable類型的,會自動合并的哦mockMvc.perform中的RequestBuilder??
  • ????????.alwaysDo(print())??//默認(rèn)每次執(zhí)行請求后都做的動作??
  • ????????.alwaysExpect(request().attribute("default",?true))?//默認(rèn)每次執(zhí)行后進(jìn)行驗(yàn)證的斷言??
  • ????????.build();??
  • ??
  • mockMvc.perform(get("/user/1"))??
  • ????????.andExpect(model().attributeExists("user")); ?
  • ?

    ?

    只要記住測試步驟,按照步驟操作,整個(gè)測試過程是非常容易理解的:

    1、準(zhǔn)備測試環(huán)境

    2、通過MockMvc執(zhí)行請求

    3.1、添加驗(yàn)證斷言

    3.2、添加結(jié)果處理器

    3.3、得到MvcResult進(jìn)行自定義斷言/進(jìn)行下一步的異步請求

    4、卸載測試環(huán)境

    總結(jié)

    以上是生活随笔為你收集整理的MockMVC的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。