mock翻译过来是‘模拟’的意思,也就是模拟接口返回的信息,用已有的信息替换接口返回的信息,从而提供仿真环境,实现模拟数据下的功能测试
因为在实际的项目研发过程中,我们经常会遇到如下的尴尬场景:
前端开发依赖于后端接口数据,但是后台人员不足或者无法立即到位,前端迟迟不能开工,或者前端小伙子自己参照ui设计图,完成对应的静态页面(没有数据交互),待后台人员到位,再进行二次开发,协助完成接口对接
[
{
"description": "any response",
"response": {
"text": "Hello, Moco"
}
}
]
java -jar moco-runner-<version>-standalone.jar http -p 12306 -c foo.json
λ java -jar "moco-runner-1.5.0-standalone.jar" http -p 12306 -c foo.json
18 九月 2023 10:01:20 [main] INFO Server is started at 12306
18 九月 2023 10:01:21 [main] INFO Shutdown port is 4726
18 九月 2023 10:01:38 [pool-1-thread-4] INFO Request received:
GET / HTTP/1.1
content-length: 0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36
Sec-Fetch-Site: none
Sec-Fetch-Dest: document
Host: 127.0.0.1:12306
Accept-Encoding: gzip, deflate, br
Sec-Fetch-Mode: navigate
sec-ch-ua: "Chromium";v="116", "Not)A;Brand";v="24", "Google Chrome";v="116"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
sec-ch-ua-platform: "Windows"
Sec-Fetch-User: ?1
Accept-Language: zh-CN,zh;q=0.9
18 九月 2023 10:01:38 [pool-1-thread-4] INFO Response return:
HTTP/1.1 200
Content-Length: 11
Content-Type: text/plain; charset=utf-8
Hello, Moco
18 九月 2023 10:01:39 [pool-1-thread-4] INFO Request received:
GET /favicon.ico HTTP/1.1
content-length: 0
Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36
Referer: http://127.0.0.1:12306/
Sec-Fetch-Site: same-origin
Sec-Fetch-Dest: image
Host: 127.0.0.1:12306
Accept-Encoding: gzip, deflate, br
Sec-Fetch-Mode: no-cors
sec-ch-ua: "Chromium";v="116", "Not)A;Brand";v="24", "Google Chrome";v="116"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Accept-Language: zh-CN,zh;q=0.9
18 九月 2023 10:01:39 [pool-1-thread-4] INFO Response return:
HTTP/1.1 200
Content-Length: 3233
Content-Type: image/png
<content is binary>
你也可以通过CURL命令行来得到
λ curl 127.0.0.1:12305
Hello, Moco1
java -jar moco-runner-1.5.0-standalone.jar --help
Moco Options:
moco [server type] -p port -c [configuration file]
server type: http, https, socket
java -jar moco-runner-<version>-standalone.jar https -p 12306 -c foo.json --https /path/to/cert.jks --cert mocohttps --keystore mocohttps
java -jar moco-runner-<version>-standalone.jar socket -p 12306 -c foo.json
java -jar moco-runner-<version>-standalone.jar http -p 12306 -c "*.json"
这样你在console中就不会看到那么多的log信息了
java -jar moco-runner-<version>-standalone.jar http -p 12306 -c foo.json -q
java -jar moco-runner-<version>-standalone.jar version
java -jar moco-runner-<version>-standalone.jar http -p 12306 -g settings.json
java -jar moco-runner-<version>-standalone.jar http -p 12306 -g env.json -e remote
env.json
[
{
"env" : "remote",
"include": "foo.json"
},
{
"env" : "local",
"include": "bar.json"
}
]
foo.json
[
{
"request" : {
"uri" : "/foo"
},
"response" : {
"text" : "foo"
}
}
]
bar.json
[
{
"request" : {
"uri" : "/bar"
},
"response" : {
"text" : "bar"
}
}
]
下面的命令定义了一个shutdown port 9527
java -jar moco-runner-<version>-standalone.jar http -p 12306 -c foo.json -s 9527
然后你就可以这样去关闭这个实例
java -jar moco-runner-<version>-standalone.jar shutdown -s 9527
类别 | 配置参数L1 | 配置参数L2 | 说明 |
---|---|---|---|
公共 | description | 描述 | |
请求 | request | 请求部分 | |
uri | 指定请求资源地址 | ||
queries | 指定查询参数 | ||
method | 指定请求方法 | ||
forms | 指定表单参数 | ||
json | 指定 JSON 请求体参数 | ||
headers | 指定请求头 | ||
响应 | response | 响应部分 | |
text | 指定响应文本 | ||
status | 指定响应状态码 | ||
headers | 指定响应头 | ||
cookies | 指定响应 cookie | ||
json | 指定响应 JSON 数据 |
demo1.json
[
{
"description":" this is your first demo",
"request" :
{
"uri" : "/foo"
},
"response" :
{
"text" : "bar"
}
}
]
curl http://127.0.0.1:12306/foo
响应:bar
注意
description
是对这个请求|响应的一个描述curl 127.0.0.1:12305/foo?a=b
这样也行response header
中的content-type是text/plain
demo2.json
[
{
"request" :
{
"uri" : "/query",
"queries" :
{
"key" : "value"
}
},
"response" :
{
"text" : "query result"
}
}
]
curl http://127.0.0.1:12305/query?key=value
响应:
query result
注意
http://127.0.0.1:12305/query
提示出错,如果http://127.0.0.1:12305/query?key=value&name=wuxianfeng
,是没问题的 "queries" :
{
"key" : "value",
"name": "wuxianfeng"
}
"key":"value"
后如果没值,这个逗号不要轻易写"key" : "value",
[
{
"request" :
{
"method" : "get",
"uri" : "/get"
},
"response" :
{
"text" : "getfoo"
}
}
]
curl http://127.0.0.1:12305/get
curl -X GET http://127.0.0.1:12305/get
都能得到getfoo
curl -X POST http://127.0.0.1:12305/get 自然就不行咯
[
{
"request" :
{
"method" : "post",
"uri" : "/post"
},
"response" :
{
"text" : "postfoo"
}
}
]
curl -X post http://127.0.0.1:12305/post
得到postfoo
[
{
"request" :
{
"method" : "post",
"uri": "/foo",
"headers" :
{
"content-type" : "application/json"
},
"json": {
"foo": "bar"
}
},
"response" :
{
"text" : "bar"
}
}
]
你可以用如下代码来调试
import requests
HOST = 'http://127.0.0.1:12305/foo'
r = requests.post(HOST,json={"foo":"bar"})
print(r.text)
注意
data=
是不会有结果的r.json()
是会报错的[
{
"request" :
{
"method" : "post",
"uri": "/foo",
"headers" :
{
"content-type" : "application/x-www-form-urlencoded"
},
"forms": {
"username": "wuxianfeng",
"password": "123456"
}
},
"response" :
{
"json" : {
"code": 200,
"msg": "login sucess"
}
}
}
]
用下面的代码调试
import requests
HOST = 'http://127.0.0.1:12305/foo'
r = requests.post(HOST,data={"username":"wuxianfeng",
"password":"123456"})
print(type(r.text)) # str
print(r.text) #是有结果的
print(type(r.json())) #dict
print(r.json())
[
{
"request" :
{
"uri" : "/cookie",
"cookies" :
{
"path" : "/"
}
},
"response" :
{
"text" : "success"
}
}
]
你可以这样
curl --cookie "path=/" http://127.0.0.1:12307/cookie
# 得到 success
也可以这样
import requests
HOST = 'http://127.0.0.1:12307/cookie'
r = requests.get(HOST,cookies={'path':'/'})
print(r.text)
[
{
"request":
{
"uri":
{
"startsWith": "/star"
}
},
"response":
{
"text": "startsWith"
}
},
{
"request":
{
"uri":
{
"endsWith": "end"
}
},
"response":
{
"text": "endsWith "
}
},
{
"request":
{
"uri":
{
"contain": "con"
}
},
"response":
{
"text": "contain "
}
}
]
测试
C:\Users\songqin008>curl http://127.0.0.1:12307/stara
startsWith
C:\Users\songqin008>curl http://127.0.0.1:12307/starb
startsWith
C:\Users\songqin008>curl http://127.0.0.1:12307/lend
endsWith
C:\Users\songqin008>curl http://127.0.0.1:12307/acon
contain
C:\Users\songqin008>curl http://127.0.0.1:12307/cona
contain
注意
/con
和/end
是一个完整的字符串"contain": "/con"
"endsWith": "/end"
[
{
"request" :
{
"uri" : "/foo"
},
"response" :
{
"text" : "foo status code",
"status" : 201
}
}
]
你可以这样
curl http://127.0.0.1:12307/foo
#得到 foo status code
或者这样
import requests
HOST = 'http://127.0.0.1:12307/foo'
r = requests.get(HOST)
print(r.status_code) #得到201
[
{
"request" :
{
"uri" : "/redirect"
},
"redirectTo" : "https://www.baidu.com"
}
]
你在地址栏访问http://127.0.0.1/redirect
就会跳转到https://www.baidu.com
[
{
"request" :
{
"uri" : "/cookie"
},
"response" :
{
"cookies" :
{
"login" : {
"value" : "true",
"domain" : "github.com",
"path" : "/",
"secure" : "true",
"httpOnly" : "true",
"maxAge": {
"duration": 1,
"unit": "hour"
},
"sameSite": "Lax"
}
}
}
}
]
地址栏访问http://127.0.0.1:12307/cookie
在响应中有如下信息
Set-Cookie:
login=true; Max-Age=3600; Expires=Tue, 19 Sep 2023 07:28:45 GMT; Path=/; Domain=github.com; Secure; HTTPOnly; SameSite=Lax
在template
字段中可以看到req的很多信息
字段 | 信息 |
---|---|
req.version | HTTP 版本号 |
req.method | 请求方法 |
req.client.address | 客户端地址 |
req.client.port | 客户端端口 |
req.queries | 查询参数 |
req.forms['username'] | 请求表单数据中username的值 |
req.headers['content-type'] | 请求头中content-type的值 |
还支持如:req.cookies['foo']
req.path.foo
req.json.foo
包括内置的一些函数${now(\"yyyy-MM-dd\")}
等
xxx.json
[
{
"request": {
"uri": "/template"
},
"response": {
"text": {
"template": "http version : ${req.version},\nmethod : ${req.method},\nclient address:${req.client.address},\nclient port:${req.client.port},\nquery params: ${req.queries['foo']}"
}
}
},
{
"request" :
{
"method" : "post",
"uri": "/template1",
"headers" :
{
"content-type" : "application/x-www-form-urlencoded"
},
"forms": {
"username": "wuxianfeng",
"password": "123456"
}
},
"response" :
{
"text": {
"template": "request info : username=${req.forms['username']},password=${req.forms['password']},\nrequest content:${req.content}"
}
}
},
{
"request" :
{
"method" : "get",
"uri": "/template2",
"headers" :
{
"content-type" : "application/json"
}
},
"response" :
{
"text": {
"template": "request headers : content-type=${req.headers['content-type']}"
}
}
}
]
调试如下
http://127.0.0.1:12305/template?foo=bar
,得到如下信息,注意?后的不能不写,不写会导致req.queries['foo']
出错http version : HTTP/1.1,
method : GET,
client address:127.0.0.1,
client port:9799,
query params: bar
import requests
HOST = 'http://127.0.0.1:12305/template1'
payload = {
"username": "wuxianfeng",
"password": "123456"
}
r = requests.post(HOST, data=payload)
print(r.text)
得到如下输出
request info : username=wuxianfeng,password=123456,
request content:username=wuxianfeng&password=123456
import requests
HOST = 'http://127.0.0.1:12305/template2'
headers = {
'content-type':'application/json'
}
r = requests.get(HOST, headers=headers)
print(r.text)
得到如下
request headers : content-type=application/json
java -Dfile.encoding=UTF-8 -jar moco-runner-1.1.0-standalone.jar http -p 9090 -c test.json