mock server 基础篇

mock,server,基础 · 浏览次数 : 6

小编点评

template = f""" request info : username={req.forms['username']},password={req.forms['password']},\request content:{req.content} """ print(template)

正文

1- mock 基础

mock翻译过来是‘模拟’的意思,也就是模拟接口返回的信息,用已有的信息替换接口返回的信息,从而提供仿真环境,实现模拟数据下的功能测试

因为在实际的项目研发过程中,我们经常会遇到如下的尴尬场景:

前端开发依赖于后端接口数据,但是后台人员不足或者无法立即到位,前端迟迟不能开工,或者前端小伙子自己参照ui设计图,完成对应的静态页面(没有数据交互),待后台人员到位,再进行二次开发,协助完成接口对接

2- moco runner 入门

下载

入门案例

  • 编写一个json文件foo.json
[
  {
      "description": "any response",
      "response": {
          "text": "Hello, Moco"
      }
  }
]
  • 运行
java -jar moco-runner-<version>-standalone.jar http -p 12306 -c foo.json
  • 在网页中输入:127.0.0.1:12306能得到如下信息

  • 在控制台会打印如下信息
λ 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>


  • Moco支持动态加载配置文件,所以无论你是修改还是添加配置文件都是不需要重启服务的

你也可以通过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
  • 支持三种服务器类型:http、https、socket
  • -p参数指定服务器的端口,你也可以不指定,那就随机分配一个,在console中会显示给你
  • -c参数指定json配置文件

HTTPS 服务器

java -jar moco-runner-<version>-standalone.jar https -p 12306 -c foo.json --https /path/to/cert.jks --cert mocohttps --keystore mocohttps

Socket 服务器

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

下面的命令定义了一个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

3- moco runner配置参数

类别 配置参数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

注意

  1. description是对这个请求|响应的一个描述
  2. /foo是区分大小写的
  3. curl 127.0.0.1:12305/foo?a=b这样也行
  4. json文件中[]是顶层结构,内部是1个或多个字典
  5. 注意格式,[]内是{},一个{}对应一个请求响应,请求是{"request":""},响应对应
  6. 请求的path是/foo对应的key是uri
  7. 在F12的响应数据中(或log中)你能看到response header中的content-type是text/plain

② request

1. query params

demo2.json

[
{
  "request" :
    {
      "uri" : "/query",
      "queries" : 
        {
          "key" : "value"
        }
    },
  "response" :
    {
      "text" : "query result"
    }
}
]
curl http://127.0.0.1:12305/query?key=value

响应:
query result

注意

  1. 如果你不带参数http://127.0.0.1:12305/query提示出错,如果http://127.0.0.1:12305/query?key=value&name=wuxianfeng,是没问题的
  2. 你可以加参数,如果这样,你至少要提供这2个参数方可,不提供参数或只提供一个都会出错,提供多了是可以的。
      "queries" : 
        {
          "key" : "value",
		  "name": "wuxianfeng"
        }
  1. 实测"key":"value"后如果没值,这个逗号不要轻易写
"key" : "value",

2. http method

  • get
[
{
"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 自然就不行咯

  • post
[
{
"request" :
  {
    "method" : "post",
    "uri" : "/post"
  },
"response" :
  {
    "text" : "postfoo"
  }
}
]
curl -X post http://127.0.0.1:12305/post
得到postfoo
  • 其他方法都是类似的,delete、head、put等等此处不再赘述

3. headers

[
{
  "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)

注意

  1. 如果你写成data=是不会有结果的
  2. 如果你写成r.json()是会报错的

4. forms

[
{
  "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)

6. operator

[
{
  "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

注意

  1. 你如果写成下面这样,你不能象上面那样访问,/con/end是一个完整的字符串
"contain": "/con"
"endsWith": "/end"
  1. 除了这3个,还有match(正则匹配),exist(存在),path(路径模式)等,详见官方

③ response

1. status code

[
{
  "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

2. redirect

[
{
  "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

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']}"
        }
    }
}
]

调试如下

  1. 地址栏访问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
  1. 要借助python代码
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
  1. python代码
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

与mock server 基础篇相似的内容:

mock server 基础篇

1- mock 基础 mock翻译过来是‘模拟’的意思,也就是模拟接口返回的信息,用已有的信息替换接口返回的信息,从而提供仿真环境,实现模拟数据下的功能测试 因为在实际的项目研发过程中,我们经常会遇到如下的尴尬场景: 前端开发依赖于后端接口数据,但是后台人员不足或者无法立即到位,前端迟迟不能开工,或

[转帖]Python-Mock接口测试

https://www.cnblogs.com/zhangwuxuan/p/12928850.html 前言 今天跟小伙伴们一起来学习一下如何编写Python脚本进行mock测试。 什么是mock? 测试桩,模拟被测对象的返回,用于测试 通常意义的mock指的就是mock server, 模拟服务端

一文教会你mock(Mockito和PowerMock双剑合璧)

Mock有模仿、伪造的含义。Mock测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法。

利用SpringBoot项目做一个Mock挡板;基于事件发布动态自定义URL和响应报文

# 导入SpringbootWEb依赖 ```xml org.springframework.boot spring-boot-starter-web ${spring-boot-start-version} org.springframework.boot spring-boot-starter-

《爆肝整理》保姆级系列教程-玩转Charles抓包神器教程(13)-Charles如何进行Mock和接口测试

1.简介 Charles最大的优势在于抓包分析,而且我们大部分使用的功能也在抓包的功能上,但是不要忘记了,Charles也可以做接口测试。至于Mock,其实在修改请求和响应数据哪里就已经介绍了,宏哥就是在这里简单的提一下介绍一下它的理论知识,今天主要介绍和分享的是使用Charles进行接口测试实操。

【码农教程】手把手教你学会Mockito使用

Mockito:简单轻量级的做mocking测试的框架。Mockito是mockito提供的核心api,提供了大量的静态方法,用于帮助我们来mock对象,验证行为等等。