在日常接口测试的工作中,经常需要依赖其他系统的API,但是联调不常有,只能自己通过mock完成数据依赖。
对于Java栈的mock工具,ThoughtWorks的前工程师郑烨编写了Moco工具,并开源在GitHub,Moco repo:https://github.com/dreamhead/moco。
Moco的优点:
- 支持http、https、socket
- 支持设置headers、cookies、statuscode
- 支持GET、POST、PUT、DELETE请求
- 只需JRE环境即可运行
- 支持热更新
- 支持json、xml、text、file数据格式
- 能与JUnit、Maven、Gradle集成
Moco的缺点:
Moco的使用很简单,配置也很方便。但也仅仅是能Stub出接口,模拟出简单的场景。
如果接收到请求后需要做一些处理,如需查询数据库、运算、或者一些复杂的操作,就无能为力了。
但是在工作中,还是可以作为一个稳定的mock工具长期部署,应用于测试中的。
一、独立使用(standalone)
只需要根据mock要求,完成mock.json的配置,启动即可。
vim mock.json
[
{
"response": {
"text": "Hello Moco"
}
}
]
启动Moco,java -jar moco-runner-0.12.0-standalone.jar http -p 8080 -c mock.json。
TIPS:更多的启动参数,参看GitHub文档。
A、设定URI
JSON中无法添加注释,利用description字段可以清楚的说明接口的功能。
[
{
"description": "设定URI",
"request": {
"uri": "/uri"
},
"response": {
"text": "Hello Moco GET URI"
}
}
]
B、设定请求方式
带参数GET请求,http://localhost:8088/getparam?id=1&status=100,参数通过queries设置k-v对。
[
{
"description": "无参GET请求",
"request": {
"uri": "/get",
"method": "get"
},
"response": {
"text": "无参GET请求返回-success"
}
},
{
"description": "带参GET请求",
"request": {
"uri": "/getparam",
"method": "get",
"queries": {
"id": "1",
"status": "100"
}
},
"response": {
"text": "带参GET请求返回-success"
}
}
]
带参数POST请求,参数通过forms设置k-v对,需要通过工具发送POST请求。
[
{
"description": "带参数POST请求",
"request": {
"uri": "/postparam",
"method": "post",
"forms": {
"id": "1",
"status": "100"
}
},
"response": {
"text": "带参POST请求返回-success",
"headers": {
"Content-Type": "text/html;charset=gbk"
}
}
}
]
C、设定Headers及请求返回为JSON
[
{
"description": "带headers信息POST请求",
"request": {
"uri": "/post/headers",
"method": "post",
"headers": {
"content-type": "application/json"
},
"json": {
"name": "isisiwish",
"sex": "male"
}
},
"response": {
"json": {
"id": "1",
"status": "100"
}
}
}
]
D、设定Cookies
如果不获取cookies,直接访问http://localhost:8088/get/with/cookies,则返回失败;如果首先访问http://localhost:8088/getcookies,获取到服务器cookies,再访问http://localhost:8088/get/with/cookies,不用额外设定cookies也可以获得正确返回。
[
{
"description": "返回cookies信息的GET请求",
"request": {
"uri": "/getcookies",
"method": "get"
},
"response": {
"cookies": {
"key": "63a9f0ea7bb98050796b649e85481845"
},
"text": "get cookies success"
}
},
{
"description": "携带cookies信息的GET请求",
"request": {
"uri": "/get/with/cookies",
"method": "get",
"cookies": {
"key": "63a9f0ea7bb98050796b649e85481845"
}
},
"response": {
"text": "the cookies is okay"
}
},
{
"description": "携带cookies信息的POST请求",
"request": {
"uri": "/post/with/cookies",
"method": "post",
"cookies": {
"key": "63a9f0ea7bb98050796b649e85481845"
},
"json": {
"name": "isisiwish",
"age": "30"
}
},
"response": {
"status": 200,
"json": {
"id": "1",
"status": "100"
}
}
}
]
E、重定向
[
{
"description": "绝对路径重定向",
"request": {
"uri": "/redirect"
},
"redirectTo": "腾讯首页"
},
{
"description": "相对重定向",
"request": {
"uri": "/redirect/top"
},
"redirectTo": "/redirect/max"
},
{
"description": "被重定向的请求",
"request": {
"uri": "/redirect/max"
},
"response": {
"text": "top == max"
}
}
]
F、返回类型为file内容
对于比较大的JSON,可以通过文件方式返回。
[
{
"request": {
"uri": "/file"
},
"response": {
"file": "data.json"
}
}
]
G、HTTPS
通过Java的keytools生成密钥,具体生成方式参考tomcat-https,启动moco时指定密钥文件即可。
java -jar moco-runner-0.12.0-standalone.jar https -p 8080 -c mock.json --https tomcat.keystore --cert 123456 --keystore 123456
H、支持多重文件引入(类似nginx的conf)
Moco支持在配置文件中引入其他配置文件,对于按照URI分组的可以通过子JSON的方式进行mock的组织,更加便于阅读和管理。
启动参数,需要从-c修改为-g,如果只想引入多个配置,可以不适用context字段。
根JSON内容如下:
[
{
"context": "/",
"include": "./json/tmall.json"
},
{
"context": "/",
"include": "./json/pdd.json"
}
]
子JSON如下:
# cat tmall.json
[
{
"description": "tmall.trades.details.tmallAdmin.get.proxy.url",
"request": {
"uri": "/si-app-openapiPROXY/router",
"method": "post"
},
"response": {
"file": "/data01/moco/json/tmall/order.json"
}
},
{
"request": {
"uri": "/prodstock/queryprodstock.xhtml",
"method": "get"
},
"response": {
"file": "/data01/moco/json/tmall/product_warehouse_stock.xml"
}
}
]
# cat pdd.json
[
{
"request": {
"uri": "/api/router",
"method": "post",
"forms": {
"type": "pdd.order.information.get"
}
},
"response": {
"json": {}
}
},
{
"request": {
"uri": "/api/router",
"method": "post",
"forms": {
"type": "pdd.invoice.application.query"
}
},
"response": {
"json": {}
}
}
]
I、正则表达式
支持正则方式对URI进行返回。
[
{
"request": {
"uri": {
"match": "/getUser/w+"
}
},
"response": {
"text": "isisiwish"
}
}
]
J、延迟返回
[
{
"request": {
"uri": {
"match": "/daily/w+"
}
},
"response": {
"latency": {
"duration": 5,
"unit": "second"
},
"text": "daily 5 second"
}
}
]
K、template
以上的请求参数的值和返回值都是固定的,从0.8版本之后,Moco提供了template功能,可以动态返回一些参数值。
[
{
"request": {
"uri": "/getInfo"
},
"response": {
"text": {
"template": "${req.queries['name']}"
}
}
}
]
template支持以下语法。
"template": "${req.version}"
"template": "${req.method}"
"template": "${req.content}"
"template": "${req.headers['foo']}"
"template": "${req.queries['foo']}"
"template": "${req.forms['foo']}"
"template": "${req.cookies['foo']}"
请求https://localhost:8088/getInfo?name=isisiwish,返回isisiwish。
更多request的设置,查看GitHub文档。
二、JUnit
Moco也支持API方式运行,可以轻松通过Maven和JUnit集成。
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>com.github.dreamhead</groupId>
<artifactId>moco-core</artifactId>
<version>0.12.0</version>
</dependency>
<!--other dependency-->
<!--利用了fluent-hc客户端请求-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>fluent-hc</artifactId>
<version>4.5</version>
</dependency>
</dependencies>
代码:
@Test
public void should_response_as_expected() throws Exception
{
// prepare a mock server
HttpServer server = httpServer(8080);
// mock.json
server.response("mock") ;
running(server, new Runnable()
{
public void run() throws IOException
{
Content content = Request.Get("http://localhost:8080").execute().returnContent();
assertThat(content.asString(), is("foo"));
}
});
}
A、大量请求模拟
实际测试工作中,会有很多接口需要mock,需要引入新的jar包。
<dependency>
<groupId>com.github.dreamhead</groupId>
<artifactId>moco-junit</artifactId>
<version>0.12.0</version>
</dependency>
<dependency>
<groupId>com.github.dreamhead</groupId>
<artifactId>moco-runner</artifactId>
<version>0.12.0</version>
</dependency>
MocoJunitRunner加载resources下的JSON配置文件,然后自动构建一个mock的服务器。
public class MocoTest
{
@Rule
public MocoJunitRunner runner = MocoJunitRunner.jsonHttpRunner(8080, Moco.pathResource("mock.json"));
@Test
public void noUriTest() throws IOException
{
Content content = Request.Get("http://localhost:8080").execute().returnContent();
assertThat(content.asString(), is("Hello Moco"));
}
@Test
public void withParamAndHeaderTest() throws IOException
{
HttpResponse httpResponse = Request.Get("http://localhost:8080/hust?param=zw").execute().returnResponse();
assertThat(httpResponse.getFirstHeader("SelfHeader").getValue(), is("SelfHeader"));
}
}
更多和JUnit的结合,查看GitHub文档。