什么是mock
mock一般常见于单元测试中。但也会在其他场景中见到,比如调用外部第三方服务时为了减少依赖,实现一个假的接口,这个接口返回的值和第三方接口返回的值是相同的,在开发环境、测试环境就调用这个假的接口,在生产环境则直接调用外部接口;这个假的接口有的公司叫挡板,有的公司叫MOCK。 微信支付mock现在很多公司使用微服务架构,比如前端和后端同时开发,但后端的接口还没有开发好,那么前端可以调用一个假的MOCK的接口完成调试消除依赖,等后端接口开发好后再完成真正的接口。
对于自动化测试人员来说,只要知道了接口定义,就可以通过接口的MOCK来调试接口的自动化测试代码。
mock框架
网上有些开源免费的MOCK框架可供使用,比如rap2, easy-mock等等。
准备工作
- 安装最新版的node
- 安装express
npm install express
- 安装supervisor
npm install supervisor
- 安装sync-request
npm install sync-request
- 安装body-parser
npm install body-parser
注意:express, supervisor, body-parser这些依赖包最好在源代码文件所在目录安装,减少一些不必要的麻烦。或者使用npm -g安装
nodejs实现的简单mock
上面提到的那些开源框架功能很强大,但也显得笨重,我们也可以根据需要快速的实现一个简单的mock server,只要修改返回的json字符串用res.send()
返回就可以很方便快捷的满足我们的需求。
源代码如下
//simple_mock.js
var express = require('express')
var app = express()
var bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
var map = {"1":{id:1,name:"bob"},"2":{id:2,name:"jack"}}
app.get('/users',function(req, res){
res.set({'Content-Type':'text/json','Encodeing':'utf8'});
res.send(map)
})
//Get方法,查找一个单一资源,在path里查询
app.get('/users/:id',function(req, res){
res.set({'Content-Type':'text/json','Encodeing':'utf8'});
res.send(map[req.param('id')])
})
//Post方法,创建一个单一资源
app.post('/users/', function(req, res){
res.set({'Content-Type':'text/json','Encodeing':'utf8'});
map[req.body.id] = req.body
res.send({status:"success",url:"/users/"+req.body.id})
})
//Put方法,更新一个单一资源
app.put('/users/:id', function(req, res){
res.set({'Content-Type':'text/json','Encodeing':'utf8'});
map[req.body.id] = req.body
res.send({status:"success",url:"/users/"+req.param('id'),device:req.body});
})
//Delete方法,删除一个单一资源
app.delete('/users/:id',function(req, res){
res.set({'Content-Type':'text/json','Encodeing':'utf8'});
delete map[req.param('id')]
res.send({status:"success",url:"/users/"+req.param('id')})
console.log(map)
})
//监听8888端口
app.listen(8888);
为了随时修改返回的数据并让修改自动生效,可以使用nodejs的supervisor模块运行mock脚本:
$ supervisor simple_mock.js
增强版的mock
有时候我们需要同时支持MOCK和真实的请求,简单的解决办法举个例子就是如果有个name参数的值传递是“张三”就转发到真实的请求并返回真实的返回值,如果不是“张三”就返回MOCK的信息。
对上面的代码稍作变化,对于GET方法,如果id是3就转发到真实的请求并返回真实的返回值,如果id不是3就返回假的mock的返回值:
//Get方法,查找一个单一资源,在query(header)里查询
app.get('/users/:id',function(req, res){
res.set({'Content-Type':'text/json','Encodeing':'utf8'});
console.log(req.param('id'))
//如果请求的ID是3,就把请求转发到真实的API,假定真实的API地址是百度;如果ID不是3,返回MOCK的信息
if(req.param('id') == '3'){
var request = require('sync-request');
var res2 = request('GET', 'http://www.baidu.com')
res.send(res2.getBody().toString())
}else{
res.send(map[req.param('id')])
}
})
如果需要返回400,500这种网络错误,直接res.send('400')
即可。
综上
上述快速实现的mock可以满足如下功能需求
- 接口的mock(GET、POST、PUT、DELETE常见请求类型)
- 同时支持mock和真实接口数据(json和其他类型)的返回
- 可以返回400或者500等各种网络错误
- 配置或者代码变更的实时生效
网友评论