脚本注入
前面我们说了谓词的注入,其实就是大同小异。
那么我们看下它的参数属性有哪些
领域 | 描述 |
---|---|
request | 请求数据都在这 |
state | mountebank全局变量,每次重启mb都会清空 |
callback | 一般情况下函数有返回值,如果没有那就是通过异步处理,此时必须使用callback调用该参数。 |
logger | log句柄的引用,在函数中可以直接使用输出日志 |
那么我们先看下代码
{
"port": 8084,
"protocol": "http",
"stubs": [{
"responses": [{
"inject": "<%- stringify(filename, './test/responses.ejs') %>"
}]
}]
}
注入模板脚本responses.ejs如下:
function(config) {
config.logger.info('origin called');
config.state.requests = config.state.requests || 0;
config.state.requests += 1;
var ret={
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ count: config.state.requests })
};
return ret;
}
其实从代码我们可以看出,上面的参数都是通过config这个对象传递给模板脚本的
state可以存放json数据、基本数据类型等。
如果修改为callback那么代码如下:
function(config) {
config.logger.info('origin called');
config.state.requests = config.state.requests || 0;
config.state.requests += 1;
var ret={
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ count: config.state.requests })
};
config.callback(ret);
}
动态行为
_behaviors这个参数通过上面的讲解,应该大家了解一二,他的任务就是修改响应的数据,那么他的行为如下:
行为 | 描述 |
---|---|
wait | 响应延迟毫秒数 |
repeat | 在转到下一个响应之前,重复一定次数的响应。 |
copy | 将请求字段中的一个或多个值复制到响应中。您可以使用正则表达式,xpath或jsonpath标记响应并从请求字段中选择值。 |
lookup | 从请求的数据中作为key值从外部数据源去取数据。 |
decorate | --allowInjection启动参数必须加在发送之前使用JavaScript注入对响应进行后处理。 |
shellTransform | --allowInjection启动参数必须加,不是使用JavaScript注入,而是将其发送到另一个应用程序,另一应用通过stdout输出JSON格式传递数据回来。 |
那么我们接下来对上面的参数详细说明下:
wait参数
{
"port": 8085,
"protocol": "http",
"stubs": [
{
"responses": [
{
"is": {
"body": "This took at least half a second to send"
},
"_behaviors": {
"wait": 500
}
}
]
}
]
}
通过http://localhost:8085访问后:
This took at least half a second to send
repeat参数
{
"port": 8085,
"protocol": "http",
"stubs": [
{
"responses": [
{
"is": {
"body": "This will repeat 2 times"
},
"_behaviors": {
"repeat": 2
}
},
{
"is": {
"body": "Then this will return"
}
}
]
}
]
}
通过http://localhost:8085访问后:
//第一次结果
This will repeat 2 times
//第二次结果
This will repeat 2 times
//第三次结果
Then this will return
从上线的结果可以看出,如果没有"repeat": 2话应该是轮询显示结果。加了以后就可以访问多少次后再往下轮询。
copy参数
{
"port": 8085,
"protocol": "http",
"stubs": [
{
"responses": [
{
"is": {
"body": "The request name was ${name}. Hello, ${name}!"
},
"_behaviors": {
"copy": [
{
"from": { "query": "name" },
"into": "${name}",
"using": {
"method": "regex",<!-- 用到正则表达式 -->
"selector": "MOUNT\\w+$",
"options": { "ignoreCase": true }<!-- 不区分大小写 -->
}
}
]
}
}
]
}
]
}
上面的代码其实就是利用请求的参数中,查找包含以mount开头的数据,然后把它替换掉name变量,
通过http://localhost:8085/400?ignore=this&name=1mountebank23访问以后,因为包含1mountebank23值,所以显示结果如下:
The request name was mountebank23. Hello, mountebank23!
如果访问http://localhost:8085/400?ignore=this&name=1mou1ntebank23,因为没有匹配
那么结果如下:
The request name was ${name}. Hello, ${name}!
lookup参数
这个参数就是从请求的数据中,取出某个值作为查询条件去外部数据源查找对应的值。
代码如下:
{
"port": 8085,
"protocol": "http",
"stubs": [
{
"responses": [
{
"is": {
"body": "Hello ${row}['Name'], have you done your ${row}['jobs'] today?"
},
"_behaviors": {
"lookup": [{<!-- 查找开始 -->
"key": {
"from": "path",<!-- 从请求路径中查找 -->
"using": { "method": "regex", "selector": "/(.*)$" },<!-- 根据斜杠匹配数据 -->
"index": 1<!-- 0会是原路径,1是去除/的值-->
},
"fromDataSource": {
"csv": {
"path": "./test/values.csv",
"keyColumn": "Name"
}
},
"into": "${row}"
}]
}
}
]
}
]
}
那么外部数据源的文件内容如下:
values.csv
State_ID,code,Name,price,tree,jobs
1111111,400,liquid,235651,mango,farmer
9856543,404,solid,54564564,orange,miner
2222222,500,water,12564,pine,shepherd
1234564,200,plasma,2656,guava,lumberjack
9999999,200,lovers,9999,dogwood,steel worker
那我通过http://localhost:8085/water访问时结果如下:
Hello water, have you done your shepherd today?
简单说明下为什么上面是index是1,懂正则的人一看就明白,但对初学者还是一个解释好,
如果路径是/water 通过下面的表达式
"using": { "method": "regex", "selector": "/(.*)$" }
得到的其实是个数组{"/water",water}
index为1就取得值为water
得到water后,然后再去values.csv文件获取到对应的行数据。
decorate参数
咱们前面在说代理是说到一个属性addDecorateBehavior,它就可以生成对应的decorate,它的的目的就是动态修改或追加响应的数据。
就是利用javascript脚本注入的方式来完成。
代码上来再说哈!
{
"port": 8085,
"protocol": "http",
"stubs": [
{
"responses": [
{
"is": {
"body": "The time is ${TIME}"
},
"_behaviors": {
"decorate": "(config) => { var pad = function (number) { return (number < 10) ? '0' + number : number.toString(); }, now = new Date(), time = pad(now.getHours()) + ':' + pad(now.getMinutes()) + ':' + pad(now.getSeconds()); config.response.body = config.response.body.replace('${TIME}', time); }"
}
}
]
}
]
}
通过http://localhost:8085访问后,结果如下:
The time is 23:06:29
当然也可以引入模板:
"_behaviors": {
"decorate": "<%- stringify(filename, './test/behaviors.ejs') %>"
}
behaviors.ejs模板文件的内容:
function(config) {
var pad = function(number) {
return (number < 10) ? '0' + number: number.toString();
},
now = new Date(),
time = pad(now.getHours()) + ':' + pad(now.getMinutes()) + ':' + pad(now.getSeconds());
config.response.body = config.response.body.replace('${TIME}', time);
}
shellTransform参数
shellTransform行为类似于decorate,可以对响应数据进行修改。但不同的地方是它通过shell命令调用外部的脚本,
执行时他会把request、response作为参数传给外部脚本,外部脚本拿到后可以对响应的数据进行修改,然后输出到控制台,这样mb就可以达到对应的值,千万注意控制台打印的是json格式。
具体代码如下:
{
"port": 8086,
"protocol": "http",
"stubs": [{
"responses": [{
"is": {
"body": "Hello, ${city}!"
},
"_behaviors": {
"shellTransform": ["node ./test/shellTransform.js"]
}
}]
}]
}
shellTransform.js文件如下
// 使用 Mock
var Mock = require('mockjs')
var request = JSON.parse(process.argv[2]),
response = JSON.parse(process.argv[3]);
response.body = response.body.replace('${city}', Mock.mock('@city'));
console.log(JSON.stringify(response));
那么通过http://localhost:8086访问后的结果如下:
Hello, 厦门市!
那么我们可以联想下,能够shellTransform.js使用外部数据源,解耦性更强了,只要外部输出json数据到控制台就可以拿到数据了。
shellTransform.js本身可以是nodejs,那么连接数据库、nosql都是分钟级的事情了,有包含上下文的业务场景挡板不就直接搞定了。
至此mountebank的使用已经讲解完了,有不明白的可以和我联系(微信号dcs678),加之前请备注mountebank或mb,否则拒绝通过。
接着看后面的实战干活哈,go on!
系统测试利器之挡板实战(一)
系统测试利器之挡板实战(二)
系统测试利器之挡板实战(三)
系统测试利器之挡板实战(四)
系统测试利器之挡板实战(六)
系统测试利器之挡板实战终结(七)