WireMock初体验,一个强大的HTTP 请求模拟测试框架
缘起
最近我创建并维护了一个开源项目 http-api-invoker ,该项目实现将 HTTP 请求和接口进行绑定,让 HTTP 接口调用跟调用本地方法一样自然优雅。在写单元测试的时候,因为需要发送 HTTP 请求,而做为一个完整独立的项目,我并不希望对它进行单测还需要依赖其他的项目。最开始我用的是 Mockito。
为了让代码更易于测试,我将真正发送请求的任务交给一个接口(Requestor),然后写了一个默认的实现类,用于发送请求。当需要测试的时候,Mock一个Requestor,于是所有请求并没有真正地发出去,只需要断言这个Mock出来的Requstor发送请求的方法有没有被正确调用就可以。
这个是使用 Mockito 的情况下,我能想到的最好的解决方案了。
但是,这里面有一个问题。默认的 Requestor 实现又如何被独立测试呢? 这让我犯难了,所以项目刚开始的时候并没有对默认的 Requestor 进行单元测试,也没有测试真正发送请求的情况下,代码的逻辑是否正确。
偶遇
不久前的某个深夜,我偶然间看到一篇 InfoQ 的上的文章 Stubbing, Mocking and Service Virtualization Differences for Test and Development Teams 让我充分了解了Mock、打桩和模拟服务的区别和应用场景,受益匪浅。在文章里面介绍了 wiremock 这个框架,于是我找到官网 ,看了一下,文档非常地清晰和完善。感觉如获至宝。
应用
我的项目刚好最需要这样的框架来做单元测试。于是我动手写了测试样例。因为官网有非常详细的文档,而且也查看了一些博客上的入门样例,很快就上手了。深深感觉到它的强大,真的非常振奋人心。具体代码可以查看 CityServiceTest 这个测试类。
使用入门
引入 maven 依赖
<dependency><groupId>com.github.tomakehurst</groupId><artifactId>wiremock-standalone</artifactId><version>2.19.0</version><scope>test</scope>
</dependency>
使用入门示例
我这里写了一个简单的测试用例,完整的真实项目用例可以查看 CityServiceTest
public class HelloWireMockTest {private static final int PORT = 18888;/*** 使用给定的端口号生成WireMockRule实例.* 这里设置之后,启动测试时 WireMock 会使用内嵌的 Jetty 启动一个 Web 服务器并监听指定的端口*/@Rulepublic WireMockRule wireMockRule = new WireMockRule(options().port(PORT));@Testpublic void helloTest() {String uri = "/say/hello";String body = "Hello World!";// 给uri打桩,这个语句表示,拦截 uri 为 /say/hello 的请求回复 "Hello World!"wireMockRule.stubFor(get(urlEqualTo(uri)).willReturn(aResponse().withBody(body)));// 这里我们可以用任何方式发起HTTP的GET请求String result = HttpUtil.get("http://localhost:" + PORT + uri);System.out.println(result);// 断言我们发出的请求返回了我们期望的结果assertEquals(result, body);}
这个测试用例跑起来的时候,WireMock会启动一个Web服务器监听 18888 端口,然后我们预设 /say/hello 接口将返回 Hello World! 这行文本做为响应,接下来我们发一个请求过去,断言拿到的是我们期望的结果。
更强大的是,当发的请求跟我们预设的不匹配的时候,它会明明白白地告诉我们,差异在哪里,例如:
而且它也支持 header 和 cookie 的验证,例如
@Testpublic void getCityWithHeaders() {Map<String, String> headers = new HashMap<>();String key = "auth";String key2 = "auth2";headers.put(key, "123");headers.put(key2, "321");int id = 1;String uri = "/city/getCityRest/" + id;City mockCity = createCity(id);wireMockRule.stubFor(get(urlEqualTo(uri))// 声明我们的请求必须包含两个指定的 header .withHeader(key, equalTo(headers.get(key))).withHeader(key2, equalTo(headers.get(key2)))// 一旦有符合要求的请求过来,则返回指定的响应.willReturn(aResponse().withBody(JSON.toJSONString(mockCity))));// 使用 http-api-invoker 框架,只需调用接口的方法,框架会发送相应的 http 请求// 这里 cityService.getCityWithHeaders 方法我们绑定的地址是 /getCityRest/{id}City result = cityService.getCityWithHeaders(id, headers);assertEquals(mockCity, result);}
如果我们发请求的时候,header 没有带上,那么控制台就会打印出下面这报告:
结语
单元测试对于写出健壮且高质量的代码非常有必要。没有单测,开发的时候就像夜里一个人走在没有灯的荒郊野岭,你永远不知道前面等待你的是小坑还是深渊,有时候出了问题自己怎么死的都不知道。而单元测试为这场野外旅行添置了一盏明灯,照亮前面的路,让你每走几步都能知道现在处在什么位置。就算掉坑里,也马上让你知道你现在在坑里,赶紧出来,以防止更糟糕的情况。
一个好的单元测试用例也有很大的学问,我相信,花一些时间学习和了解这些技能是一本万利的事情。与君共勉。
WireMock初体验,一个强大的HTTP 请求模拟测试框架相关推荐
- Mockito:一个强大的用于Java开发的模拟测试框架
介绍 本文将介绍模拟测试框架Mockito的一些基础概念, 介绍该框架的优点,讲解应用Mockito的Java示例. 模拟(Mock)的概念 在软件开发的世界之外, "mock"一 ...
- 【Web安全】一款功能强大的Web身份认证测试框架
关于Raider Raider是一款功能强大的Web身份认证测试框架,该框架被设计用来测试Web应用程序的身份认证机制.虽然像ZAProxy和Burpsuite这样的Web代理工具同样可以允许研究人员 ...
- 一个强大而简单的 Python Web框架:web.py
From:https://www.oschina.net/question/5189_4306 Web.py github 地址:https://github.com/webpy/webpy ...
- H5初体验~一个新手H5前端开发的笔记
在平凡的事物中,探寻人间的美好. 一.H5开发简介 h5是HTML5 是升级版的HTML标准 1.优势 (1)跨平台性!兼容性好,用H5搭建的站点与应用可以兼容PC端与移动端.Windows与Linu ...
- 一个强大的工具来模拟数百万并发用户负载测试:Gryphon
Gryphon是由网易自主研发的能够模拟千万级别并发用户的一个软件,目的是能够用较少的资源来模拟出大量并发用户,并且能够更加真实地进行压力测试, 以解决网络消息推送服务方面的压力测试的问题和传统压力测 ...
- 我的Go+语言初体验——【三、spx案例测试(附-视频)】
欢迎大家参与[我的Go+语言初体验]活动: 活动地址:[https://bbs.csdn.net/topics/603464006?utm_source=1594742339] 安装过程博文:[我的G ...
- Flutter初体验(二)—— 创建第一个Flutter APP
Flutter初体验(二)--- 创建第一个Flutter APP 在第一篇文章 Flutter初体验(一)---Mac 安装配置,学习了配置 Flutter 开发环境,并运行了Demo项目,本篇根据 ...
- 我的Go+语言初体验——在Docker建立一个可以用Go+语言开发的容器环境(以Ubuntu容器为例)
前言 "我的Go+语言初体验" | 征文活动进行中...... 作为一名嵌入式软件工程师的我,在工作中使用高级语言开发的场景不多,但技术的迭代大部分偏向于应用层开发,身为程序员的一 ...
- Vue初体验(七)使用Vue实现一个简单的聊天框
1.实践是检验真理的唯一标准,现在我们做一个简易的聊天窗口,有一个input框,用于用户输入,一个按钮button,用于把用户的输入提交上去,然后又一个列表ul,用于展示我们每次提交的消息. 2.通过 ...
最新文章
- 硬不硬你说了算!近 40 张图解被问千百遍的 TCP 三次握手和四次挥手面试题
- gvim 编辑器初学
- 对dropout的理解详细版
- Liunx 安装mysql 5.6.16
- P3501-[POI2010]ANT-Antisymmetry【hash,二分答案】
- 录播图的分页使用进度条形式显示
- 用java画网状图_如何在背景中绘制一个带网格线的漂亮条形图?
- java 通过eclipse编辑器用mysql尝试 连接数据库
- [转贴]壮观啊!实拍中国最美公路
- php数组中去掉空格,php数组如何去除空格
- linux远程桌面密钥,使用 SSH 密钥连接到 Linux VM - Azure Virtual Machines | Microsoft Docs...
- c语言:输入三角形的边长求面积
- 如何清除redis缓存
- ubuntu服务器设置定时自动开关机
- Linux下用rar压缩和解压文件
- 入行大数据,需要学习哪些编程语言?
- Win10ahci模式怎么开启?
- 操作系统——Liunx系统基础知识
- 应届生就业高峰期,Java程序员面试常犯的5点错误总结
- 【朴素贝叶斯】深入浅出讲解朴素贝叶斯算法(公式、原理)