@xiaoqq
2016-12-09T13:20:26.000000Z
字数 4261
阅读 2830
Mock
大公司的岗位泾渭分明,大家各司其职,一起把事情做好。当项目开始时,前后端同时进行,那么问题来了,后端还未开发完,无法给前端提供真正的接口,而前端需要调试怎么办?就只好自己伪造(Mock)数据和请求。
的方法有多种
根据接口文档,手工Mock数据;这种方式不需要额外的方式辅助,简洁快速,可以随意Mock自己想要的数据,缺点是无法生成大量的数据,数据是死的,没有随机性;
根据接口文档,定义Mock数据的模板,使用生成Mock数据的工具(比如:faker.js、Mock.js);优点是快速高效,修改起来方便,缺点当后端接口改变时需要再次修改Mock数据模板,还有就是遇到某种极端的情况无法Mock(比如:需要一个数组的数据加起来等于100%);
在接口文档中定义好模板规则,当后端修改接口时,会自动根据接口生成新的Mock数据(比如:swagger);缺点是操作比较复杂,而且需要后端人员配合。
有了Mock的数据,还需要Mock数据请求(get, post, put...)。
直接在前端代码中Mock请求,这种方式虽然最简便,但是也带来了风险,如果前端人员在真实环境中忘记去除Mock的数据请求,那么就可能造成难以估量的结果;而且由开发环境切换到真实环境中也需要一定的成本;还有,这种方式很难模拟请求的响应速度;
通过fiddler或者charles等代理的工具,这种方式消除了上述的弊端,但是缺点是灵活性较差,当配置项较多的时候,维护成本也会随之上升巨大;
使用MockServer来Mock请求(比如:json-server、puer、puer-mock),缺点是配置复杂,有一定的学习成本,但是灵活高效,可以快速地配置多种请求,比如搜索、过滤、分页、排序等。
综合考虑,我准备使用mock.js+json-server来打造运营后台的mock-server.
一直在思考mock数据选择faker.js还是Mock.js, 最后综合考虑,觉得Mock.js
有良好的文档和可扩展性,而且还是阿里的大神些的,所以最终选择了Mock.js。
Mock.js的文档在这里:https://github.com/nuysoft/Mock/wiki/Getting-Started
使用起来很简单:
var data = Mock.mock(tpl);
其中tpl
就是数据模板,Mock.js最厉害之处就是它的模板配置非常灵活。
数据模板分为三个部分:属性名、生成规则、属性值。
'name|rule': value
生成规则有以下七种格式:
属性值(value)支持占位符,写法:@占位符(参数 [, 参数]),此外,属性值还可以是函数或者正则表达式。
Mock.js对于运营后台的Mock数据的需求还是远远不够的。
我对Mock.js做了如下几点扩展:
Mock.js支持生成随机日期,但是却无法指定在一定范围内生成。
扩展:
// 返回date1和date2之间的日期
between: function(date1, date2, format) {
var min = new Date(date1);
var max = new Date(date2);
format = format || 'HH:mm:ss'
var date = new Date(Math.random() * (max.getTime() - min.getTime()) + min.getTime());
return this._formatDate(date, format)
},
使用方法:
"createTime": '@between(2016-06-01, 2016-12-31, yyyy-MM-dd HH:mm:ss)',
"updateTime": '@between(@createTime, 2016-12-31, yyyy-MM-dd HH:mm:ss)',
Mock.js自增('name|+step': value
)所生成的数据必须是正序排列的,但是有些数据需要倒序排列。
为了解决这个问题,我引入了第八种生成规则的格式:name|min-max+r
,其中,+r表示对该数组进行翻转
扩展:
首先将正则表达式改为如下,使之能够匹配到('+r'),并且将其作为rule.parameters
的第五个参数
RE_KEY: /(.+)\|(?:\+(\d+)|([\+\-]?\d+-?[\+\-]?\d*)?(?:\.(\d+-?\d*))?(\+r)?)/,
然后Handler.extend.array
中将数组翻转:
if (options.rule.parameters[5] == '+r') {
result = result.reverse();
}
使用方法:
"moduleConf|1-17+r": [{
"weight|+1": 0
}]
这段模板会生成随机生成1-17个数组,每个数组的weight是从x-0倒序排列的。
Mock.js的占位符只能找到当前的字段,对于父元素或者根元素的字段却无能为力。
为此,我对现有的占位符进行了修改:@root.value
或者@parent.value
其中,root和parent分别表示根级上下文和父级上下文。
扩展:
首先,对Handler.extend.string
进行修改:
if (ph.startsWith('@root.')) {
phed = Handler.placeholder(ph.replace('@root.', "@"), options.context.root, options.context.templateCurrentContext, options)
} else if (ph.startsWith('@parent.')) {
phed = Handler.placeholder(ph.replace('@parent.', "@"), options.context.parent, options.context.templateCurrentContext, options)
} else {
phed = Handler.placeholder(ph, options.context.currentContext, options.context.templateCurrentContext, options)
}
在options.context
中有root
这个参数,但是却没有parent
这个参数,所以,要从外层将options.context.currentContext
传过来
Handler.gen(options.template[i], i, {
path: options.context.path,
templatePath: options.context.templatePath,
currentContext: result,
templateCurrentContext: options.template,
root: options.context.root || result,
templateRoot: options.context.templateRoot || options.template,
parent: options.context.currentContext || result
})
此外,在Handler.extend.object
中还需要判断一下,上层是否为数组,如果上层为数组,则取上上层的context
var parentContext;
if (typeof options.context.path[options.context.path.length - 2] == "number") {
parentContext = options.context.parent || result
} else {
parentContext = options.context.currentContext || result
}
使用方式
{
"id": 1,
"moduleConf|1-17": [{
"groupId": '@parent.id',
}],
"moduleConf2|1-17": {
"groupId": '@parent.id',
}
}
在对象和数组的groundId都可以取到父级的id值。
运营后台还有一些很奇葩的要求,比如某个字段下面的所有数组,有一个percent字段,这些字段的总和必须为100。这里我写的比较死。
扩展:
在Handler.extend.array
中,生成options.rule.count
个随机数
//生成总数为100的options.rule.count个随机数
var rndSum = 0;
var rndArr = [];
for (var rndi = 0; rndi < options.rule.count; rndi++) {
var rnd = Math.random() + 0.05
rndArr.push(rnd)
rndSum += rnd
}
rndArr = rndArr.map(function(r) {
return Math.floor(r / rndSum * 100 + 0.5)
})
rndSum = 0;
for (rndi = 1; rndi < options.rule.count; rndi++) {
rndSum += rndArr[rndi];
}
rndArr[0] = 100 - rndSum;
然后将模板中percent字段的value替换掉
//如果模板中有percent,则将percent替换为百分比
for (var key in optTemplate) {
if (key == 'percent') {
optTemplate[key] = rndArr[i]
}
}
使用方法:
"pageConf|1-10": [{
"percent": 10,
}]
在给pageConf随机生成1至10个数组,并且保证这些数组的percent值的和为100。