系统测试利器之挡板实战(五)

脚本注入

前面我们说了谓词的注入,其实就是大同小异。
那么我们看下它的参数属性有哪些

领域 描述
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!

系统测试利器之挡板实战(一)
系统测试利器之挡板实战(二)
系统测试利器之挡板实战(三)
系统测试利器之挡板实战(四)
系统测试利器之挡板实战(六)
系统测试利器之挡板实战终结(七)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352

推荐阅读更多精彩内容