高手都这么给 Spring MVC 做单元测试!

本章节主要讲解以下两部分内容:

1、Mock 测试简介

2、测试用例演示

一、Mock 测试简介

1、什么是 mock 测试

在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个「虚拟的对象」来创建以便测试的测试方法,就是 「mock 测试」在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个「虚拟的对象」来创建以便测试的测试方法,就是mock 测试。

虚拟的对象就是 mock 对象。

mock 对象就是真实对象在调试期间的代替品。

2、为什么使用 mock 测试

避免开发模块之间的耦合

轻量、简单、灵活

3、MockMVC 介绍

基于 RESTful 风格的 SpringMVC 的测试,我们可以测试完整的 Spring MVC 流程,即从 URL 请求到控制器处理,再到视图渲染都可以测试。

1)MockMvcBuilder

MockMvcBuilder 是用来构造 MockMvc 的构造器,其主要有两个实现:StandaloneMockMvcBuilder 和 DefaultMockMvcBuilder,对于我们来说直接使用「静态工厂 MockMvcBuilders 创建」即可。

2)MockMvcBuilders

负责创建 MockMvcBuilder 对象,有两种创建方式:

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

「webAppContextSetup」(WebApplicationContext wac):指定 WebApplicationContext,将会从该上下文获取相应的控制器并得到相应的 MockMvc,本章节下面测试用例均使用这种方式创建 MockMvcBuilder 对象。

3)MockMvc

对于服务器端的 SpringMVC 测试支持主入口点。通过 MockMvcBuilder 构造 MockMvcBuilder 由 MockMvcBuilders 建造者的静态方法去建造。

核心方法:perform(RequestBuilder rb) -- 执行一个 RequestBuilder 请求,会自动执行 SpringMVC 的流程并映射到相应的控制器执行处理,该方法的返回值是一个 ResultActions。

4)ResultActions

(1)「andExpect」:添加 ResultMatcher 验证规则,验证控制器执行完成后结果是否正确;

(2)「andDo」:添加 ResultHandler 结果处理器,比如调试时打印结果到控制台;

(3)「andReturn」:最后返回相应的 「MvcResult」;然后进行自定义验证 / 进行下一步的异步处理;

5)MockMvcRequestBuilders

用来构建请求的,其主要有两个子类 「MockHttpServletRequestBuilder *和」MockMultipartHttpServletRequestBuilder*(如文件上传使用),即用来 Mock 客户端请求需要的所有数据。

6)MockMvcResultMatchers

(1)用来匹配执行完请求后的「结果验证」

(2)如果匹配失败将抛出相应的异常

(3)包含了很多验证 API 方法

7)MockMvcResultHandlers

(1)结果处理器,表示要对结果做点什么事情

(2)比如此处使用 MockMvcResultHandlers.print() 输出整个响应结果信息

8)MvcResult

(1)单元测试执行结果,可以针对执行结果进行「自定义验证逻辑」

二、测试用例演示

1、添加依赖

<!-- spring 单元测试组件包 -->

<dependency>

 <groupId>org.springframework</groupId>

 <artifactId>spring-test</artifactId>

 <version>5.0.7.RELEASE</version>

</dependency>

<!-- 单元测试Junit -->

<dependency>

 <groupId>junit</groupId>

 <artifactId>junit</artifactId>

 <version>4.12</version>

</dependency>

<!-- Mock测试使用的json-path依赖 -->

<dependency>

 <groupId>com.jayway.jsonpath</groupId>

 <artifactId>json-path</artifactId>

 <version>2.2.0</version>

</dependency>

前两个 jar 依赖我们都已经接触过了,对于返回视图方法的测试这两个 jar 依赖已经足够了,第三个 jar 依赖是用于处理返回 Json 数据方法的,这里要明白每个 jar 的具体作用。

2、被测试的方法

@RequestMapping(value ="editItem")

public String editItem(Integer id, Model model) {

Item item = itemService.getItemById(id);

model.addAttribute("item", item);

return"itemEdit";

}

@RequestMapping(value ="getItem")

@ResponseBody

public Item getItem(Integer id) {

Item item = itemService.getItemById(id);

returnitem;

}

这里我们提供了两个方法,一个是返回视图的方法,另一个是返回 Json 数据的方法,下面我们会给出测试类,分别对这两个方法进行测试。

3、测试类:ItemMockTest

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations ="classpath:spring/*.xml")

@WebAppConfiguration

public class ItemMockTest {

@Autowired

private WebApplicationContext context;

private MockMvc mockMvc;

@Before

public voidinit() {

mockMvc = MockMvcBuilders.webAppContextSetup(context).build();

}

}

这里前两个注解就不再解释了,我们在学习 Spring 与 Junit 整合的时候已经讲解过了,这里说一下第三个注解:@WebAppConfiguration:可以在单元测试的时候,不用启动 Servlet 容器,就可以获取一个 Web 应用上下文。

1)返回视图方法测试

@Test

public voidtest() throws Exception {

MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/editItem").param("id","1"))

.andExpect(MockMvcResultMatchers.view().name("itemEdit"))

.andExpect(MockMvcResultMatchers.status().isOk())

.andDo(MockMvcResultHandlers.print())

.andReturn();

Assert.assertNotNull(result.getModelAndView().getModel().get("item"));

}

这三句代码是我们对结果的期望,最后打印出了结果,说明执行成功,所有期望都达到了,否则会直接报错。从结果中我们就可以看到这个请求测试的情况。

2、返回 Json 数据方法

@Test

public void test1() throws Exception {

mockMvc.perform(MockMvcRequestBuilders.get("/getItem")

.param("id","1")

.accept(MediaType.APPLICATION_JSON))

.andExpect(MockMvcResultMatchers.status().isOk())

.andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))

.andExpect(MockMvcResultMatchers.jsonPath("$.id").value(1))

.andExpect(MockMvcResultMatchers.jsonPath("$.name").value("IPhone X"))

.andDo(MockMvcResultHandlers.print())

.andReturn();

}

在这个方法中比较特殊的就是设置 MediaType 类型,因为都是使用 Json 格式,所以设置了 MediaType.APPLICATION_JSON,jsonPath 用于比对期望的数据是否与返回的结果一致,这里需要注意的是 "$.id" 这 key 的种形式。

四、小结

这里只是用到了 MockMvc 很小一部分知识,更加深入学习会使你养成一种良好编写单元测试的习惯,这是十分难得的一种好习惯,推荐去看官方文档,然后动手去测试一下,为你编写的每一个 Controller 方法进行测试,保证他们的可靠性。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容

  • 最近在搞微服务的项目,搞完后发现内部需要调用别的服务的接口,可是另一个服务还没有写完我还调不通,哪这就非常尴尬了。...
    Java小白锅阅读 1,158评论 0 0
  • 单元测试 在写完功能之后,自然就是测试来验证自己controller接口是可运行的 采用的是MockMvc的框架 ...
    每日一坑阅读 428评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,656评论 18 139
  • SpringMVC测试框架 基于RESTful风格的SpringMVC的测试,我们可以测试完整的Spring MV...
    小陈阿飞阅读 897评论 0 0
  • Spring Boot 应用的测试 《Spring Boot 实战开发》(陈光剑)—— 基于 Gradle + K...
    光剑书架上的书阅读 1,024评论 1 3