在前端项目中,前端测试并无被重视,缘由有不少,好比 学习/研发成本高,团队不够重视,或者项目不合适等,在这里咱们不去追究是什么缘由致使这种现象,可是有一点我很肯定,形成这种缘由,还有一个更重要的缘由,就是 “意识不到位”,即便有不少同窗了解过单元测试,可是也不知道如何应用到 “项目” 中,针对这种现象,咱们从一个简单却很常见的小项目,来打开测试工程化
冰山一角html
在刷题的过程当中,咱们常常会使用一个项目用于练习写笔试题,好比排序,查找之类的算法题目前端
新建一个工程,目录以下node
├── index.js ├── index.html └── src └── search.js
search.js
和index.js
便可console.log(binarySearch([1],1)===0)
二分法查找
和顺序查找
函数/** * 二分法 * @param {Array} arr */ function binarySearch(arr, expected) { let start = 0 let end = arr.length - 1 while (start <= end) { let mid = parseInt(start + (end - start) / 2) let value = arr[mid] if (value === expected) { return mid } else if (value > expected) { end = mid } else { start = mid } } return -1 } /** * 顺序查找 * @param {*} arr * @param {*} expected */ function sequentialSearch(arr, expected) { let i = 0 while (i > arr.length) { let value = arr[i] if (value === expected) { return i } i++ } return -1 }
OK,大功告成,把页面拖到浏览器中直接运行,连服务器都省了~~!
当我准备为我这个完美的项目鼓掌的时候,眼角瞟到个人座右铭,成为一个专业的大前端,此时此刻 专业这个词格外刺眼,做为新世纪好青年,我怎么可能让别人质疑个人专业,因而我要继续装(入)逼(坑)
git
. ├── node_modules └── test └── test.js └── src └── search.js ├── package.json ├── .gitignore ├── index.js
在 package.json 配置算法
{ .... "scripts":{ "test":"node test/test.js" } }
对应 js的模块 要改为commonjs
规范
search.js 调整npm
function binarySearch(){ //todo } function sequentialSearch(){ //todo } module.exports = { binarySearch, sequentialSearch }
index.js 调整json
const { binarySearch,sequentialSearch } = require('./src/search') module.exports = { binarySearch, sequentialSearch }
test.js 调整,为了让提示更加明显点,咱们尝试让描述更加丰富点数组
const { binarySearch,sequentialSearch } = require('../index') console.log(‘二分查找: [1]的1在数组0位置上’,binarySearch([1],1)===0) console.log(‘二分查找:[1,2,3]的1在数组0位置上’,binarySearch([1,2,3],1)===0) console.log(‘二分查找:[1,2,3]的2在数组1位置上’,binarySearch([1,2,3],2)===0) console.log(‘顺序查找:[1]的1在数组0位置上’,sequentialSearch([1],1)===0) console.log(‘顺序查找:[1,2,3]的1在数组0位置上’,sequentialSearch([1,2,3],1)===0) console.log(‘顺序查找:[1,2,3]的2在数组1位置上’,sequentialSearch([1,2,3],2)===0)
一顿操做猛如虎以后,感受完美的一笔~~
我火烧眉毛,运行 npm run test
promise
二分查找:[1]的1在数组0位置上 true 二分查找:[1,2,3]的1在数组0位置上 true 二分查找:[1,2,3]的2在数组1位置上 false 顺序查找:[1]的1在数组0位置上 false 顺序查找:[1,2,3]的1在数组0位置上 false 顺序查找:[1,2,3]的2在数组1位置上 false
咱们发现 有几点不足:浏览器
为了解决 青铜时代 遗留下很多体验问题,咱们不得不封装一些方法,强化console的输出,文档输出,可视化等输出,然而咱们所作的一切强化,都是新概念 测试框架的雏形,不过在正式介绍 测试框架前,咱们先了解下 断言
“我×,测试框架?断言?这尼玛又是什么?”
断言是单元测试中用来保证最小单元是否正常的检测方法,用于判断逻辑执行是否达到开发者预期的表达式,断言在运行的过程当中,若断言不为真,程序会停止运行
“经常使用的断言库有哪些?”
咱们先简单学习 assert, 做为Nodejs内置核心模块,无需引用,最为 断言 入门库最为合适
## assert
var assert=require('assert') assert.equal(Math.max(1,100),100)
一旦 assert.equal()不知足指望,将会抛出AssertionError
异常,整个程序将会中止运行
经常使用的检测方法
“感受脑袋疼,能不能通俗点?”
先来一个例子,压压惊,咱们把青铜时代的代码优化下
console.log(‘顺序查找:[1]的1在数组0位置上’,sequentialSearch([1],1)===0) //为了通用性,咱们把sequentialSearch([1],1)===0 提炼出来 function equal(actual,expected,message){ return actual===expected?message:`${actual}!==${expected}` } console.log(‘顺序查找:[1]的1在数组0位置上’,equal(sequentialSearch([1],1),0,'成功'))
通俗的说 就是 equal
这个方法就是断言
“我迷迷糊糊的貌似明白了一点,那我运行一下尝尝鲜吧”
test/index.js
const assert = chai.assert const { binarySearch } = require('../index') assert.equal(binarySearch([1], 1), 0)//成功 assert.equal(binarySearch([1], 1), 1)//失败 assert.equal(binarySearch([1,2], 2), 1)//成功 assert.equal(binarySearch([1,2], 1), 0)//失败
运行 node test/index.js
//失败输出 AssertionError: expected 0 to equal 1 at Object.<anonymous> (F:\learn\test\index.js:19:8)
“呃....我以为这体验,也青铜时代差很少”
咱们能够看到,在第二个测试用例执行时,发现代码执行失败后,直接退出程序,同时提示你 指望值
和实际运行值
,以及对于错误代码相关提示
等等。错误提示方面比封装equire
方法强大很多;可是,依旧不能让我愿意使用它。
没错,断言拿到很是重要错误信息;可是他没有解决体验问题;若是说 断言是里子,那测试框架 就是面子
“测试框架是什么?”
测试框架 通俗的说就是专门 服务于代码块测试 的解决方案,他主要有如下功能
“经常使用的测试框架有哪些?”
通俗的说,测试框架 就是 管理/执行断言,他和断言一块儿使用将会更增强大
mocha 是一款强大的测试框架,可以运行在nodejs和浏览器中,可以高效的管理测试用例,支持多种测试报告格式
支持两种测试风格:TDD/BDD
经常使用方法
TDD
使用suite
pending
表示hook-用于协助describe
中测试用例的准备·安装·卸载和回收等工做,Hook
通常用于describe
内,但也能够describe
外,做为顶级Hook
describe
时触发执行describe
中每一个测试用例执行前和执行后触发执行Full example
test/index.js
describe('hooks', function() { before(function() { console.log('before') }); after(function() { console.log('after') }); beforeEach(function() { console.log('beforeEach') }); afterEach(function() { console.log('afterEach') }); it('Test1',()=>{ console.log('test1') }) it('Test2',()=>{ console.log('test2') }) // test cases });
运行 npm run test
{ "script":{ " test":"mocha" } }
hooks
before
beforeEach
test1
√ Test1
afterEach
beforeEach
test2
1) Test2
afterEach
after
1 passing (15ms)
1 failing
1) hooks
Test2: AssertionError: expected 0 to equal 1 + expected - actual -0 +1 at Context.it (test\index.js:93:12)
咱们能够看到 基于mocha后的断言,他的提示体验大大的提高 - 成功后,有相关提示 - 遇到失败时,依旧能够执行下去,展现全部失败用例信息 - 统计测试用例成功数和失败数 4. **异步处理** - done
it('should save without error', (done)=> { var user = new User('Luna'); user.save((err)=> { if (err) done(err); else done(); }); //user.save(done); }); ``` - promise ```ts it('respond with matching records', ()=> { return db.find({type: 'User'}).should.eventually.have.length(3); }); ``` - async/await ```ts it('responds with matching records', async function() { const users = await db.find({type: 'User'}); users.should.have.length(3); }); ```
Only-屏蔽其余测试单元/测试用例,只执行标识为Only的测试单元/用例。通常用于 当你的单元测试越写越多时,只想测试新写的单元测试是否正确,这个属性就能够帮你在执行时,帮你过滤掉其余测试,加快执行速度
describe.only('something', function() { // 只会跑包在里面的测试 })
或者
it.only('do do', () => { // 只会跑这一个测试 })
skip-表示执行时,跳过标识的测试单元/测试用例,能够做用于describe
和it
it.skip('should return -1 unless present', function() { // 代码不存被执行 }); it('should return the index when present', function() { // 代码会执行 });
能够this.skip()
在测试用例执行的时候,根据运行时过滤当前测试案例
describe('outer', function() { before(function() { this.skip(); }); after(function() { // will be executed }); describe('inner', function() { before(function() { // will be skipped }); after(function() { // will be skipped }); }); });