facebook三大项目:yarn jest metro,有横扫宇宙之势。 而jest项目的宗旨为:减小测试一个项目所花费的时间成本和认知成本。 ——其实,它在让你当一个好老师。jest文档很是简略、难以阅读, 所以才有了这篇文章。 jest是vue、react和vue-cli技术栈的重要一环,也是当前最值得掌握的测试框架,对此你须要达到很熟悉的程度。
本文github地址: https://github.com/wanthering...vue
教育和测试,是相通的。node
你能够野路子自学,但掌握系统化、体系化的知识,终归离不开一个好老师。react
测试能够不写,但当你面对大型复杂的项目之时,没有测试框架步履维艰。ios
如今,你能够跟我一步一步学会jest,你将懂得:为何jest是优雅、简洁而符合人性的,而且终将成为测试界的惟一的、最佳的解决方案。git
想象一下,当你走上讲台,五十多个孩子静静地看着你。红扑扑的脸蛋,大大的眼睛。es6
接下来,你将课本上知识教给他们了一遍,github
函数运行过程,就至关于你的教学过程。web
请同窗们跟我一块儿敲下代码:vue-cli
(请在项目下建立一个文件:lesson1.js
)npm
lesson1.js
/** * 加法,便是将多个数值逐个累加 */ exports.sum = (...args) => { let res = 0 for (let i of args) { res += i } return res } /** * 乘法,便是将b个重复的数值a,进行累加 */ exports.times = (a, b) => { let resArr = (new Array(b)).fill(a) return exports.sum(...resArr) }
以上文件涉及es6和nodejs模块化的基础知识,初看可能并很差理解,但相信我,你敲完如下的测试代码,就会理解它的含义——就像教会一个学生同样。
就像你js工程师面临的永恒难题同样——真的能跑通吗?
当老师的你,心里也无比惶恐,第一次教这些,他们真的能懂吗?
这时须要用上jest进行测试,使用npm安装:
npm i jest -S
一个合格的老师,会作这几个步骤:
建立一个lesson1.test.js
lesson1.test.js
const {sum, times} = require('./lesson1') test('同窗,请问这个累加的结果是什么?',()=>{ expect(sum(2+2+2+2+2+2)).toBe(12) }) test('同窗,请问这个乘法的结果是什么?',()=>{ expect(times(2,6)).toBe(12) }) test('那么,两个数值的结果是否相等呢?',()=>{ expect(times(2,6)).toEqual(sum(2+2+2+2+2+2)) })
这时须要运行jest命令,你能够全局安装jest:
npm i jest -g
而后
jest lesson1.test.js
也能够在package json的test字段下写入
... "scripts": { "test": "jest" }, ...
而后命令行输入
npm test
若是你使用的webstorm等IDE的话,文档中直接显示绿色小键头,点击就是了。
接下来,会看到一路pass,证实lesson1.js文件无误。
咱们读书这么多年,深知好老师和坏老师的区别:
上课照本宣科,就像直接写下满纸js代码同样,这是赖皮狗老师的专长。
但一个优秀的老师,他会:
若是你不是很熟悉jest框架提供的各种匹配器,这里有一份小抄送给你:jest-cheat-sheet
你看,jest所作的,没有一丝多余步骤,也没少一个必要步骤,这正是咱们这些年遇到的好老师的共有特征,也正是jest测试的极致之处。
jest在异步过程当中也很是方便!
咱们先使用json-server
创建服务器,再使用axios
获取数据。
这两个npm包使用很是普遍,熟悉的axios封装的能够直接拷贝server.js
和request.js
代码。
下载:
npm i json-server axios -S
建立server.js文件
server.js
const jsonServer = require('json-server') const defaultData = () => ({ 'lesson': [ { 'id': 1, 'title': 'how to add', 'teacher': 'Miss Wang' }, { 'id': 2, 'title': 'how to multiply', 'teacher': 'Mr Liu' }, { 'id': 3, 'title': 'how to subtract', 'teacher': 'Ms Han' } ], 'homework': [ { 'id': 1, 'works': ['add','multiply'], 'student': 'Jim Green' }, { 'id': 2, 'title': ['add','subtract'], 'student': 'lily' }, { 'id': 3, 'title': ['add','subtract'], 'student': 'lucy' }, { 'id': 4, 'title': ['add','subtract','multiply'], 'student': 'Han Mei Mei' }, { 'id': 5, 'title': ['subtract','multiply'], 'student': 'Li Lei' } ], 'exam': { 'name': 'primary school final exam' } }) const createJSONServer = (data = defaultData()) =>{ const server = jsonServer.create() const router = jsonServer.router(data) const middlewares = jsonServer.defaults() server.use(middlewares) server.use(router) return server } createJSONServer().listen(3000) console.log('3000端口已联通')
建立request.js文件
request.js
const axios = require( 'axios' ) class HttpRequest { constructor(baseUrl = 'http://localhost:3000') { this.baseUrl = baseUrl } /** * 返回默认配置 */ getInsideConfig() { return { baseURL: this.baseUrl, headers: {} } } /** * 响应栏截,返回指定格式信息 */ interceptors(instance) { instance.interceptors.response.use(res => { const {data} = res return data }, error => { return Promise.reject(error) }) } /** * 处理网络请求 */ request(options) { const instance = axios.create() options = Object.assign(this.getInsideConfig(), options) this.interceptors(instance) return instance(options) } } /** * 导出request模块 */ exports.requestPromise = (port,method='get')=>{ const Http = new HttpRequest('http://localhost:3000') return Http.request({ url: port, method }) } exports.requestCallback = (cb,port,method='get')=>{ const Http = new HttpRequest('http://localhost:3000') Http.request({ url: port, method }).then(data=>{ // ▽请注释掉下面一行,再试一试回调可否跑通? cb(data) }) }
使用node server
跑起服务,咱们就能够开始测试异步回调了。
班上来了一个坏学生,上课从很差好听课,恰恰人缘又特别好。
这时,你提问让坏学生回答,他只是安静地站起来,什么都不作,而后过了一会对你说:“老师,这道题我回答过了啊!”
同时,全班同窗都点头“嗯嗯他回答过了”。
这时候,你,该怎么办? 有没有感觉到深深的绝望?
看一看如下的例子。建立lesson2.test.js,并写入
lesson2.test.js
const {requestPromise, requestCallback} = require('./request') test('异步callback方式检测', () => { // 下面进行了抛出了两次断言,在断言以前能够 function callback (data){ expect(data).toStrictEqual({'id': 1, 'title': 'how to add', 'teacher': 'Miss Wang'}) } requestCallback(callback,'lesson/1') })
跑通了,彷佛一切正常。。。
但当咱们回到request.js
注释掉cb(data)
时,咱们知道回调函数并不返回数据,测试理应不经过。然而。。
仍是跑通了!
这是由于requestCallback根本就没有进入函数体,而测试函数,只要不报错,都算经过。
异步回调,就是这样一个坏透了的学生,常常装做回答过了蒙混过关。
做为老师,弄死坏学生的方法可能你本身想到了:
“上黑板写,写完告诉我!”
你能够提供一个在测试函数内提供一个done,done必需要调用后,才能算作测试经过。
lesson2.test.js
test('异步callback方式检测', done => { // 下面进行了抛出了两次断言,在断言以前能够 function callback (data){ expect(data).toStrictEqual({'id': 1, 'title': 'how to add', 'teacher': 'Miss Wang'}) done() } requestCallback(callback,'lesson/1') })
这样,就必需要运行了callback才能经过测试了,不然就会超时报错。
除了以上方式之外,你还能够检验函数体内的断言跑了几回
test('异步callback方式检测,无done', () => { // 下面进行了抛出了两次断言,在断言以前能够 expect.assertions(1); function callback (data){ expect(data).toStrictEqual({'id': 1, 'title': 'how to add', 'teacher': 'Miss Wang'}) } requestCallback(callback,'lesson/1') })
expect.assertions(1)
表示, 断言语句expect(xxx).toXXX(xxx)
必须跑通一次,将要检验多个“坏学生”异步回调的时候,这招犹其有效。
有坏学生,天然有好学和普通学生,promise就是一名“普通的学生”
lesson2.test.js
test('异步Promise方式检测', () => { expect.assertions(1); return requestPromise('exam').then(data => { expect(data).toStrictEqual({'name': 'primary school final exam'}) }) })
检验异步Promise时,必需要用return
返回,不然它就像“坏学生”同样,直接蒙混过关溜走了。
你还可使用使用.resolve/.reject形式
lesson2.test.js
test('异步Promise方式被成功resolve', () => { expect.assertions(1); return expect(requestPromise('exam')).resolves.toStrictEqual({'name': 'primary school final exam'}) });
若是须要检验Promise被reject:
test('异步Promise方式被reject', () => { expect.assertions(1); return expect(requestPromise('exam')).rejects.toMatch('error') });
上课从不迟到、校服永远一尘不染、做业按时永远上交、上课认真作笔记、回答问题完美无缺、别人不听课她还会打!小!报!告!
这就是咱们的async/await,咱们应该多一些这样的三好学生。
lesson2.test.js
test('异步async/await方式检测', async () => { // 下面进行了抛出了两次断言,在断言以前能够 expect.assertions(2) const lesson1 = await requestPromise('lesson/1') const homework3 = await requestPromise('homework/3') expect(lesson1).toStrictEqual({'id': 1, 'title': 'how to add', 'teacher': 'Miss Wang'}) expect(homework3).toMatchObject({'student': 'lucy'}) })
优雅,温馨、简洁、大方,无需多言,async/await值得你拥有。
虽然咱们不少时候仍是在和异步回调、异步Promise打交道...
假如不是简单的测试同步返回、测试异步返回,而是须要记录执行过程当中的状态呢?
const forEach = (arr, fn) => { if (!arr.length || !fn) return let i = -1 let len = arr.length while (++i < len) { let item = arr[i] fn(item, i, arr) } }
假如遇到这样一个循环函数,内部的运行状态就不太可能经过返回值来知晓了。这时,你须要Mock函数。
测试同步返回值、异步返回值,就像是上课,这只是老师的本份。
而学生大部分时间,都是自习、吃饭、宿舍,老师想管到这一部分,就须要派出让人闻风丧脸的存在——五道杠·无间道·小报告之王·风纪委员。
她平时混迹在普通学生之中,或者说,她就是一名再普通不过的学生。但,当她遇到老师——即在test()测试体内——一点儿陈芝麻烂谷的破事,都会被抖露出来。
lesson3.test.js
//经过jest.fn()建立Mock Function const mockCallback = jest.fn(x => 42 + x); //将mockCallback代入forEach运行一次,便可记录下全部的值 forEach([0, 1], mockCallback); test('记录mockCallback函数运行过程',()=>{ // mockCallback上报函数运行了两次 expect(mockCallback.mock.calls.length).toBe(2); // mockCallback上报函数第一次运行的输入为0 expect(mockCallback.mock.calls[0][0]).toBe(0); // mockCallback上报函数第二次运行的输入为1 expect(mockCallback.mock.calls[1][0]).toBe(1); // The return value of the first call to the function was 42 // mockCallback上报函数第一次运行的结果为42 expect(mockCallback.mock.results[0].value).toBe(42); })
提起教师,随处可见的朋友圈、公众号、贺卡
短信里面,满是鸡汤般的口号:“人类灵魂工程师”、“燃烧本身,照亮他人”“无私”“奉献”“爱心”。
但,教师的本职——最高效率地辅助学生构建的完整知识体系。 专业性的观点却被选择性忽视。
软件开发也是,人人在谈测试驱动,人人都在强调测试的重要性,测试彷佛成了一个形而上学的感性概念。
但时间和人力成本上、框架的专业性、框架的掌握成本的诸多限制,使大多数项目测试至关于无。另外一方面,少数高度测试覆盖的项目又显得十分笨拙,测试耗费的精力竟然比coding还长...
幸之,得益于jest测试框架的产生,一个极致简洁
功能强大、语义清晰的测试终于呈如今咱们面前。让开发与测试相辅相成,而非时间加倍。
而最新的vue技术栈正在全面采用jest测试框架。
今后,testing之对于coding,如同孤独的钢琴曲中,缓缓传来小提琴的和弦,顿时锦瑟和鸣,心灵震颤无以复加。
前面我已经介绍了 AST抽象语法树,点击连接地址,下一期,将结合AST带来测试驱动开发实战,这,将是读懂vue-cli三、并掌握vue全方位技术栈的第一步。