mock翻译过来是模仿的意思,Server是服务器。粗暴点直译就是模仿服务器。

写在前面

通过阅读本文,你将对Mock的使用有一定的了解,对前后端分离的概念有了更深一步的认识,对Koa的使用有一定的了解。本文先从背景出发去抛出“我们为什么要用Mock?”的灵魂拷问,紧接着我们通过Mock在前后端的使用来进行实战落地,最后我们再总结回顾,展望高配版的Mock Server。

本文不会像念经一样把官方文档的API抄一遍告诉读者这个怎么用,那个怎么用,更多地是提供一个思路或者想法以及项目的落地带着大家学习Mock的使用。因为我坚信“官方文档始终是最权威的文档。”,所以“Do Not Repeat"原则,不要做念经这种事情,因为官方文档写的已经很详细了。还有就是有些项目API茫茫多,如果都全面地写一遍,累死啦,这个是官方文档干的事情。技术只有转换成生产力,才是程序员的赚钱的核心竞争力,劝君莫惜金缕衣,劝君惜取少年时。

这里简单地罗列下Mock的整体知识,读者后续可以根据这个大纲有选择地去看。

API

  • Mock.mock()
  • Mock.setup()
  • Mock.random()
  • Mock.valid()
  • Mock.toJSONSchema()

据不完全统计,Mock支持18种数据定义,172种数据定义写法。具体的参见:http://mockjs.com/examples.html

参见:https://github.com/ataola/node-blacksmith/blob/master/code/framework/koa-study/koa-mock/mock/random/basic.js

使用Mock的背景

我们为什么要使用Mock?

传统的非前后端分离的项目,后端老哥除了要做对接服务器数据库相关的工作,还要搞前端页面,太多太累太杂了。随着时代的发展、人类社会的进步,编程技术的更新迭代,慢慢地开始有了专职的前端程序员和后端程序员等等,项目越来越复杂,前后端的要求度逐步提高,尤其是Node.JS技术的迅猛发展,十一年弹指一挥间,在npm、github各类库和项目如雨后春笋般蹭蹭蹭地雄起,给开发者提供了很多解决方案,这也使得前后端分离成为可能。事物存在的即是合理的,但我们也要辩证地去看待这个事物。前后端分离项目的落地比前后端不分离的落地增加了开发人员对接沟通的成本,在某些场景下,前端开发会受限制于后端开发,接地气地说就是后端接口没写好没提供前端可能就无从下手了,为了解决这个问题,我们需要进行相关地Mock,来模拟后端返回的数据也好或者后端的接口也好,总之,我们需要一个Mock Server。

Mock在前端的使用

安装

# npm安装
npm i mockjs -D

引入方式

传统script脚本引入

去Bootcdn引入相关的脚本,地址:https://www.bootcdn.cn/Mock.js/, 形如

<!-- 生产环境 -->
<script src="https://cdn.bootcdn.net/ajax/libs/Mock.js/0.1.1/mock-min.js"></script>
<!-- 开发环境 -->
<script src="https://cdn.bootcdn.net/ajax/libs/Mock.js/0.1.1/mock.js"></script>

ES Module

import Mock from 'mockjs';

CommonJS

const Mock = require('mockjs');

Mock.mock( rurl?, rtype?, template|function( options ) )使用

  • rurl: 当拦截到匹配 rurl 的 Ajax 请求时,将根据数据模板 template 生成模拟数据,并作为响应数据返回
  • rtype:当拦截到匹配rtype 的 Ajax 请求时,将根据数据模板 template 生成模拟数据,并作为响应数据返回。
  • template:生成模拟数据的模板
  • function: 当拦截到匹配 rurl 的 Ajax 请求时,函数 function(options) 将被执行,并把执行结果作为响应数据返回。

具体的参见:https://github.com/ataola/node-blacksmith/tree/master/code/framework/koa-study/koa-mock/static

Mock在后端的使用

在前面我们了解了Mock在前端的使用,我们还需要思考这么一个问题,模拟也要模拟的深沉一点,也就是像一点,前面的写法足以应付大部分场景,但是有的时候我们需要拟合后端的服务,比如网络的延迟、跨域、性能等等问题,我们更加期望是搞一个服务器,模拟后端的一些API行为。作为前端选手,Javascript天然会,既然用了Javascript的基础,我们自然而然地会想到用Node.JS去搭建一个后端服务。

笔者这里使用Koa搭建一个后端服务,主体代码如下:

const http = require('http');

const Koa = require('koa');
const app = new Koa();
const logger = require('koa-logger');
const bodyparser = require('koa-bodyparser')
const onerror = require('koa-onerror');
const errorMiddleware = require('./middlewares/error');
const ipBlackListMiddleware = require('./middlewares/ip_blacklist');
const { host, port, ip_blacklist } = require('./config/index'); // import routes
const IndexRoute = require('./routes/index');
const MockRoute = require('./routes/mock'); // error handler
onerror(app); app.use(ipBlackListMiddleware(ip_blacklist)); // when post, use x-www-form-urlencoded or json
app.use(bodyparser({
enableTypes:['json', 'form', 'text']
})); // use koa-logger
app.use(logger()); // routes middleware
app.use(IndexRoute.routes(), IndexRoute.allowedMethods());
app.use(MockRoute.routes(), MockRoute.allowedMethods()); // error-handling
app.on('error', errorMiddleware()); // create a server
const server = http.createServer(app.callback()); // listen port
server.listen(port, host, () => {
console.log(`mock server is running in http://${host}:${port}`);
}); module.exports = server;

大致的一个流程是,导入了项目的npm包,中间件、路由,初始化Koa实例,调用了相关的中间件和路由,最后监听服务器端口。

如果对Mock不是很熟,我们大致会这样做,把相关返回信息写在JSON文件中或者js文件中,然后通过引入或者读取相关文件来做这件事

JSON文件形式

{
"data": {
"name": "zjt",
"age": 23
},
"success": true,
"code": 1,
"message": "获取用户信息成功"
}

定义完返回格式后,我们可以通过commonJS的语法用require引入,也可以通过内置的fs模块的读取文件的函数去读取这部分JSON的内容,然后把它衔接到相关路由上面构成一个Mock API。

形如:

const user_json = require('../mock/json/user.json');

router.get('/json/user', async ctx => {
ctx.body = user_json;
});

JS文件形式

这里仿照楼上也是类似的。

const user_js = require('../mock/js/user');

router.get('/js/user', async ctx => {
ctx.body = user_js;
});

这样做的话,能够满足我们日常生活中的大部分开发,但是太费劲了,每次我们都要写这么多一坨坨的JSON或者JS文件,我们希望这个Mock Server能够更加智能一点,本着”简单、短小精悍“的原则去思考,我们自然而然会想到引入Mock.JS去做这件事情。

Mock.JS的应用

这里我们思考一个例子,最常见的就以返回用户身份信息为例。我们就意思下,罗列一下用户常见的属性,比如说用户id、用户名字、用户昵称、用户生日、用户地址、用户邮箱、能量值(也可以理解成阳光值)、创建时间、更新时间

const Mock = require('mockjs');

const data = Mock.mock({
'data|4-10': [{
'id': '@id',
'name': '@cname',
'nickname|1': ['沉鱼', '落雁', '闭月', '羞花'],
'birthday': '@date',
'address': '@county(true)',
'email': '@email',
'power|1-5': '★',
'created': '@now',
'updated': '@now'
}]
}); module.exports = {
data,
success: true,
code: 1,
message: '获取用户数据成功'
};

简单的讲下

  • 'data|4-10'[{}]: 表示有个数组data,它里面至少有4个对象,上限10个对象
  • @id: 表示数据占位符定义,一个id
  • @name: 表示数据占位符定义,一个name
  • 'nickname|1': ['沉鱼', '落雁', '闭月', '羞花'],: 表示nickname为一个字符串,值为沉鱼落雁闭月羞花中的一个。
  • @date: 表示数据占位符定义,一个形如1997-06-13这样的日期
  • @county(true): 表示数据占位符定义, 一个形如江苏省 淮安市 金湖县这样的地址
  • @email: 表示数据占位符定义,一个邮箱
  • 'power|1-5': '★': 表示有个字符串,值为最少1颗星,最多5颗星,其实这个做外卖五分好评或者老师课程评价这种数据展示应景一些
  • @now: 表示当前时间。

最后的效果就是

这里我们可以看出Mock的结果还是有些不可控性,比如我就想让它显示正常点的邮箱、可读性强一点的段落文字,这里就要用到文中的沉鱼落雁闭月羞花的例子,我们事先准备好部分结果集让其Mock数据。

Mock数据的单元测试

这里我是结合Mocha(测试框架)、chai(断言)、supertest(模拟http测试)对Mock的API进行了一个单元测试,具体的如下:

const app = require('../server');
const supertest = require('supertest')(app);
const expect = require('chai').expect; describe('mock Server', () => {
describe('#GET /', () => {
it('should return a response with HTTP code 200', function(done) {
supertest
.get('/')
.expect(200, done);
});
}); describe('#GET /mock/js/user', () => {
it('response data success should return true', (done) => {
supertest
.get('/mock/js/user')
.expect(200)
.end((err, res) => {
if (err) {
done(err);
}
const { code, data, message, success } = res.body;
expect(res.statusCode).to.equal(200);
expect(res.body).to.be.an('object');
expect(code).to.eql(1);
expect(data).to.eql({ name: 'ataola', skill: 'node.js' });
expect(message).to.eql('获取用户信息成功');
expect(success).to.eql(true);
done();
});
});
});
});

高配版的Mock Server

站在产品经理的角度,我想,高配版的Mock Server就是打开浏览器,有个界面给你点点点进行增删改查,然后生成一个API,有兴趣的童鞋可以去实现下,溜了溜了。。。

最后

本文选自“Node.JS打铁”系列文章,项目地址:https://github.com/ataola/node-blacksmith

文中涉及到的项目例子地址:https://github.com/ataola/node-blacksmith/tree/master/code/framework/koa-study/koa-mock

参考文献

Mock.JS官网: http://mockjs.com/

MockJS 文档:https://github.com/nuysoft/Mock/wiki

MockJS 示例:http://mockjs.com/examples.html

MockJS语法规范:https://github.com/nuysoft/Mock/wiki/Syntax-Specification

Mock.Mock()的使用:https://github.com/nuysoft/Mock/wiki/Mock.mock()

搭建一个低配版的Mock Server的更多相关文章

  1. 【Node/JavaScript】论一个低配版Web实时通信库是如何实现的( WebSocket篇)

    引论 simple-socket是我写的一个"低配版"的Web实时通信工具(相对于Socket.io),在参考了相关源码和资料的基础上,实现了前后端实时互通的基本功能 选用了Web ...

  2. 【Java】利用注解和反射实现一个"低配版"的依赖注入

    在Spring中,我们可以通过 @Autowired注解的方式为一个方法中注入参数,那么这种方法背后到底发生了什么呢,这篇文章将讲述如何用Java的注解和反射实现一个“低配版”的依赖注入. 下面是我们 ...

  3. 【JavaScript】论一个低配版Web实时通信库是如何实现的之二( EventSource篇)

    前情提要 「 话说上回说到!那WebSocket大侠,巧借http之内力,破了敌阵的双工鸳鸯锁,终于突出重围. 然而玄难未了,此时web森林中飞出一只银头红缨枪,划破夜色. "莫非!?&qu ...

  4. 基于canvas和web audio实现低配版MikuTap

    导言 最近发掘了一个特别happy的网页小游戏--MikuTap.打开之后沉迷了一下午,导致开发工作没做完差点就要删库跑路了,还好boss瞥了我一眼就没下文了.于是第二天我就继续沉迷,随着一阵抽搐,这 ...

  5. 搭建react项目(低配版)

    react项目低配版,可作为react相关测试的基础环境,方便快速进行测试. git clone git@github.com:whosMeya/simple-react-app.git git ch ...

  6. Jenkins 结合 Docker 为 .NET Core 项目实现低配版的 CI&CD

    随着项目的不断增多,最开始单体项目手动执行 docker build 命令,手动发布项目就不再适用了.一两个项目可能还吃得消,10 多个项目每天让你构建一次还是够呛.即便你的项目少,每次花费在发布上面 ...

  7. unittest框架(惨不忍睹低配版)

    根据我上个随笔的unittest框架优化得来,虽然对于smtp模块还是有点迷糊,不过还是勉强搭建运行成功了,还是先上代码: #login_test.py import requests class L ...

  8. 分享一个低配VPS下运行的mysql配置文件

    在各种内存CPU核心只有1/2核,内存只有512M/1G的vps下,内存.CPU.硬盘都不是太充裕.因此主要思路是,禁止吃内存大户innodb引擎,默认使用MyISAM.禁止吃硬盘大户log-bin, ...

  9. java线程学习第一天__低配版的卖面包机

    package Thread;import javax.xml.bind.ValidationEvent;class snacks{    private int  SaledSnacks=0;   ...

随机推荐

  1. Python 实现 T00ls 自动签到脚本(邮件+钉钉通知)

    T00ls 每日签到是可以获取 TuBi 的,由于常常忘记签到,导致损失了很多 TuBi .于是在 T00ls 论坛搜索了一下,发现有不少大佬都写了自己的签到脚本,签到功能实现.定时任务执行以及签到提 ...

  2. JS 执行机制笔记

        js同步和异步同步 前一个任务结束以后再执行下面一个任务,程序的执行顺序与任务的排列顺序是一致的 同步任务都在主线程上执行,形成一个执行线 异步 前一个任务没结束之前程序还可以执行别的任务 j ...

  3. C#LeetCode刷题之#326-3的幂(Power of Three)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3867 访问. 给定一个整数,写一个函数来判断它是否是 3 的幂次 ...

  4. C#LeetCode刷题之#707-设计链表(Design Linked List)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4118 访问. 设计链表的实现.您可以选择使用单链表或双链表.单链 ...

  5. LeetCode 120. Triangle (三角形最小路径和)详解

    题目详情 给定一个三角形,找出自顶向下的最小路径和.每一步只能移动到下一行中相邻的结点上. 例如,给定三角形: [ [2], [3,4], [6,5,7], [4,1,8,3] ] 自顶向下的最小路径 ...

  6. Spring Boot 2.x基础教程:使用集中式缓存Redis

    之前我们介绍了两种进程内缓存的用法,包括Spring Boot默认使用的ConcurrentMap缓存以及缓存框架EhCache.虽然EhCache已经能够适用很多应用场景,但是由于EhCache是进 ...

  7. 旧 WCF 项目迁移到 asp.net core + gRPC 的尝试

    一个月前,公司的运行WCF的windows服务器down掉了,由于 AWS 没有通知,没有能第一时间发现问题. 所以,客户提出将WCF服务由C#改为JAVA,在Linux上面运行:一方面,AWS对Li ...

  8. Kafka 为什么快

    Kafka 为什么能那么快 | Kafka高效读写数据的原因 无论 kafka 作为 MQ 也好,作为存储层也罢,无非就是两个功能(好简单的样子),一是 Producer 生产的数据存到 broker ...

  9. day6 函数

    1.关键字参数     给实参对应的形参   调用函数时 设置关键字参数,形参=实参,把实参固定给那个形参 2.元组的可变(不定长参数)的使用      可变参数可以接收任意数量的普通的形参,并且组包 ...

  10. 关于数据库新建用户提示“用户、组或角色‘’XXX‘’在当前数据库中已已存在”的解决办法

    一般在还原数据库后,给这个数据库添加一个登录名时出现. 例如数据库备份文件中已经包含了用户abc,现在还原了数据库,然后发现现有数据库中没有abc这个用户,想要新建一个abc用户,作为该数据库的own ...