在之前的 Spring学习之旅(八)--SpringMVC请求参数 我们是通过在控制台输出来验证参数是否正确,但是这样做实在是太耗时间了,我们今天来学习下 MockMvc,它可以让我们不需要启动项目就能调用接口并验证接口返回结果是否符合我们的预期。

为何使用MockMvc?

MockMvc 实现了对 Http 请求的模拟,能够直接使用网络的形式,实现 Controller 的调用,这样可以使得测试速度快、不依赖网络环境,而且提供了一套验证的工具,这样可以使得请求的验证统一而且很方便。

如何使用 MockMvc

MockMvcBuilder 是用来构造 MockMvc 的构造器,主要有两个实现:

  • StandaloneMockMvcBuilder
  • DefaultMockMvcBuilder

分别对应两种测试方式,即独立安装和集成 Web 环境测试(此种方式并不会集成真正的 web 环境,而是通过相应的 Mock API 进行模拟测试,无须启动服务器)。对于我们来说直接使用静态工厂 MockMvcBuilders 创建即可。

集成Web环境方式

MockMvcBuilders.webAppContextSetup(WebApplicationContext context) :指定 WebApplicationContext,将会从该上下文获取相应的控制器并得到相应的 MockMvc

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = RootConfig.class)
@WebAppConfiguration
public class RequestParameterControllerTest { @Autowired
private WebApplicationContext wac; private MockMvc mockMvc; @Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
}

独立测试方式

MockMvcBuilders.standaloneSetup(Object... controllers) :通过参数指定一组控制器,这样就不需要从上下文获取了;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = RootConfig.class)
@WebAppConfiguration
public class RequestParameterControllerTest { @Autowired
private WebApplicationContext wac; private MockMvc mockMvc; @Before
public void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(new RequestParameterController()).build();
}
}

实例

Controller:

@Controller
public class RequestParameterController { @RequestMapping("/toInt")
@ResponseBody
public int toInt(int value) {
return value;
}
}

单元测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = RootConfig.class)
@WebAppConfiguration
public class RequestParameterControllerTest { @Autowired
private WebApplicationContext wac; private MockMvc mockMvc; @Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
} @Test
public void toInt() throws Exception {
mockMvc.perform(
// 发送 GET 请求
MockMvcRequestBuilders.get("/toInteger?value=3"))
// 判断HTTP响应码
.andExpect(MockMvcResultMatchers.status().isOk())
// 判断返回内容是否是预期值
.andExpect(MockMvcResultMatchers.content().string("3"))
// 输出整个响应结果信息
.andDo(MockMvcResultHandlers.print());
} }

控制台输出:

MockHttpServletRequest:
HTTP Method = GET
Request URI = /toInteger
Parameters = {value=[3]}
Headers = {} Handler:
Type = com.marklogzhu.web.controller.RequestParameterController Async:
Async started = false
Async result = null Resolved Exception:
Type = null ModelAndView:
View name = null
View = null
Model = null FlashMap:
Attributes = null MockHttpServletResponse:
Status = 200
Error message = null
Headers = {Content-Type=[text/plain;charset=ISO-8859-1], Content-Length=[1]}
Content type = text/plain;charset=ISO-8859-1
Body = 3
Forwarded URL = null
Redirected URL = null
Cookies = [] Process finished with exit code 0

常用对象

MockMvcRequestBuilders

MockMvcRequestBuilders: 用来构建请求。

方法 作用
MockHttpServletRequestBuilder get(String urlTemplate, Object... urlVariables) 发送 GET 请求
MockHttpServletRequestBuilder post(String urlTemplate, Object... urlVariables) 发送 POST 请求
MockHttpServletRequestBuilder put(String urlTemplate, Object... urlVariables) 发送 PUT 请求
MockHttpServletRequestBuilder delete(String urlTemplate, Object... urlVariables) 发送 DELETE 请求
MockHttpServletRequestBuilder options(String urlTemplate, Object... urlVariables) 发送 OPTIONS 请求
MockHttpServletRequestBuilder request(HttpMethod httpMethod, String urlTemplate, Object... urlVariables) 提供自己的Http请求方法及uri模板和uri变量
MockMultipartHttpServletRequestBuilder fileUpload(String urlTemplate, Object... urlVariables) 发送文件上传请求
RequestBuilder asyncDispatch(final MvcResult mvcResult) 创建一个启动异步处理的请求的 MvcResult 进行异步分派的RequestBuilder

ResultActions

调用 MockMvc.perform(RequestBuilder requestBuilder) 后将得到 ResultActions,通过 ResultActions 可以完成如下三件事:

  • ResultActions andExpect(ResultMatcher matcher) :添加验证断言来判断执行请求后的结果是否是预期的;
  • ResultActions andDo(ResultHandler handler) :添加结果处理器,用于对验证成功后执行的动作,如输出下请求/结果信息用于调试;
  • MvcResult andReturn() :返回验证成功后的MvcResult;用于自定义验证/下一步的异步处理;

ResultMatcher

方法 作用
HandlerResultMatchers handler() 请求的 Handler 验证器,比如验证处理器类型/方法名;此处的 Handler 其实就是处理请求的控制器
RequestResultMatchers request() 得到 RequestResultMatchers 验证器
ModelResultMatchers model() 得到模型验证器
ViewResultMatchers view() 得到视图验证器
FlashAttributeResultMatchers flash() 得到 Flash 属性验证
StatusResultMatchers status() 得到响应状态验证器
HeaderResultMatchers header() 得到响应 Header 验证器
CookieResultMatchers cookie() 得到响应 Cookie 验证器
ContentResultMatchers content() 得到响应内容验证器
JsonPathResultMatchers jsonPath(String expression, Object ... args) 得到Json表达式验证器
ResultMatcher jsonPath(String expression, Matcher matcher) 得到Json表达式验证器
XpathResultMatchers xpath(String expression, Object... args) 得到Xpath表达式验证器
XpathResultMatchers xpath(String expression, Map<string, string=""> namespaces, Object... args) 得到Xpath表达式验证器
ResultMatcher forwardedUrl(final String expectedUrl) 验证处理完请求后转发的url(绝对匹配)
ResultMatcher forwardedUrlPattern(final String urlPattern) 验证处理完请求后转发的url(Ant风格模式匹配,@since spring4)
ResultMatcher redirectedUrl(final String expectedUrl) 验证处理完请求后重定向的url(绝对匹配)
ResultMatcher redirectedUrlPattern(final String expectedUrl) 验证处理完请求后重定向的url(Ant风格模式匹配,@since spring4)

实例

JSON请求/响应验证

String requestBody = "{\"id\":1, \"name\":\"zhang\"}";
mockMvc.perform(post("/user")
.contentType(MediaType.APPLICATION_JSON).content(requestBody)
.accept(MediaType.APPLICATION_JSON)) //执行请求
.andExpect(content().contentType(MediaType.APPLICATION_JSON)) //验证响应contentType
.andExpect(jsonPath("$.id").value(1)); //使用Json path 验证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)) //执行请求
.andExpect(status().isBadRequest()) //400错误请求
.andReturn(); Assert.assertTrue(HttpMessageNotReadableException.class.isAssignableFrom(result.getResolvedException().getClass()));//错误的请求内容体

文件上传

byte[] bytes = new byte[] {1, 2};
mockMvc.perform(fileUpload("/user/{id}/icon", 1L).file("icon", bytes)) //执行文件上传
.andExpect(model().attribute("icon", bytes)) //验证属性相等性
.andExpect(view().name("success")); //验证视图

自定义验证

MvcResult result = mockMvc.perform(get("/user/{id}", 1))//执行请求
.andReturn(); //返回MvcResult
Assert.assertNotNull(result.getModelAndView().getModel().get("user")); //自定义断言

Spring学习之旅(十)--MockMvc的更多相关文章

  1. Spring学习之旅(十五)--SpringBoot

    在使用 Spring 的过程中,有时候会出现一些 ClassNotFoundException 异常,这是因为 JAR 依赖之间的版本不匹配所导致的.而 Spring Boot 就能避免绝大多数依赖版 ...

  2. Spring学习之旅(十四)--缓存

    数据库的读写并发一直都是应用性能的瓶颈所在之一,针对改动频率很小的数据我们应该将他存放到缓存中,减少与数据库的交互. 启用对缓存的支持 Spring 对缓存的支持有两种方式: 注解驱动的缓存 XML ...

  3. Spring学习之旅(十二)--持久化框架

    对于本职工作来说 JDBC 就可以很好的完成,但是当我们对持久化的需求变得更复杂时,如: 延迟加载 预先抓取 级联 JDBC 就不能满足了,我们需要使用 ORM框架 来实现这些需求. Spring 对 ...

  4. Java框架spring 学习笔记(十八):事务管理(xml配置文件管理)

    在Java框架spring 学习笔记(十八):事务操作中,有一个问题: package cn.service; import cn.dao.OrderDao; public class OrderSe ...

  5. Spring学习之旅(八)Spring 基于AspectJ注解配置的AOP编程工作原理初探

    由小编的上篇博文可以一窥基于AspectJ注解配置的AOP编程实现. 本文一下未贴出的相关代码示例请关注小编的上篇博文<Spring学习之旅(七)基于XML配置与基于AspectJ注解配置的AO ...

  6. Spring学习之旅(六)--SpringMVC集成

    对大多数 Java 开发来说,基于 web 的应用程序是我们主要的关注点. Spring 也提供了对于 web 的支持,基于 MVC 模式的 Spring MVC 能够帮助我们灵活和松耦合的完成 we ...

  7. Java框架spring 学习笔记(十四):注解aop操作

    回见Java框架spring Boot学习笔记(十三):aop实例操作,这里介绍注解aop操作 首先编写一个切入点HelloWorld.java package com.example.spring; ...

  8. Spring学习之旅(十三)--使用NoSQL数据库

    除了关系型数据库之外,现在还有一种 NoSQL 数据库非常流行,而 Spring 自然也没有放过对它的支持. NoSQL 数据库有很多种,如: MongoDBGenericJackson2JsonRe ...

  9. Spring学习之旅(三)--装配Bean

    装配 Bean 的方式 在 XML 中进行显式配置 在 Java 中进行显式配置 隐式的 Bean 发现机制和自动装配 Spring 提供了以上三种方式进行 Bean 的配置,可以根据自己的需求选择一 ...

随机推荐

  1. NPOI 日期类型的判断

    NPOI目前我用到有两套类,一套是为了读写XLS:一套是读写XLSX 在读取文件时大都会判断单元格类型,方式大同小异,只有日期类型不同. 默认日期类型的单元格在NPOI都认为是数值类型(CellTyp ...

  2. 开源分布式事务中间件Seata使用指南

    介绍 Seata 是阿里巴巴开源的分布式事务中间件,一种分布式事务解决方案,具有高性能和易于使用的微服务架构. 初衷 对业务无侵入:即减少技术架构上的微服务化所带来的分布式事务问题对业务的侵入 高性能 ...

  3. java - 如何使一个类不能被继承

    使用final关键字: 使用私有构造器: public final class InitTest{ private InitTest(){} }

  4. jango简介

    Django简介   Django框架简介 MVC框架和MTV框架 MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Mode ...

  5. PHP与ECMAScript_3_常用字符串函数

      PHP ECMAScript 长度 strlen($str) str.length     查找类 $str[n]                                          ...

  6. bean的创建(五)第五部分 属性填充

    AbstractAutowireCapableBeanFactory.populateBean protected void populateBean(String beanName, RootBea ...

  7. 关于HTML的引入CSS文件问题

    一 html代码引用外部css文件时若css文件在本文件的父目录下的其他目录下,可使用绝对路径.此时路径要写为  “ ../ ”形式,如在tomcat下建立一个test文件,在该文件中建立两个文件 夹 ...

  8. 基于ReentrantLock的非公平锁理解AQS

    AQS AQS概述 ​ AbstractQueuedSynchronizer抽象队列同步器简称AQS,它是实现同步器的基础组件,juc下面Lock的实现以及一些并发工具类就是通过AQS来实现的,这里我 ...

  9. RabbitMQ搭建单机及集群

    1,基本环境配置 hosts 文件 免密登录 2,访问官网 https://www.rabbitmq.com/download.html 3, 4,安装依赖 yum -y install make g ...

  10. ASP.NET Core Identity自定义数据库结构和完全使用Dapper而非EntityFramework Core

    前言 原本本节内容是不存在的,出于有几个人问到了我:我想使用ASP.NET Core Identity,但是我又不想使用默认生成的数据库表,想自定义一套,我想要使用ASP.NE Core Identi ...