Mocha学习笔记
Mocha是一个JavaScript领域优秀的单元测试框架,可以在Node.js或者浏览器环境下运行。Mocha让异步测试变得简单而有趣,它支持灵活的、精确的测试报告,可以把未捕获异常映射到特定的测试用例中。
执行下面的命令添加为当前工程的依赖:
1 |
npm install --save-dev mocha |
所谓测试风格,是指测试用例的组织方式。流行的单元测是风格包括:
- TDD,测试驱动开发。关注所有功能是否正确实现,每个功能点都具备对应的测试用例
- BDD,行为驱动开发。关注应用程序的整体行为是否正确
mocha使用基于JavaScript的DSL语言扩展,对两种测试风格进行支持。
TDD风格的用于主要使用suite、test来组织测试代码。suite表示一个测试套件,可以形成多层级的结构,具体到一个测试用例时,使用test。TDD风格提供了 setup 、 teardown 两个钩子方法,分别在进入/退出suite时执行。代码示例:
1 2 3 4 5 6 7 8 9 10 |
suite( 'Array', function () { setup( function () { } ); suite( '#indexOf()', function () { // 一个测试用例 test( 'should return -1 when not present', function () { assert.equal( -1, [ 1, 2, 3 ].indexOf( 4 ) ); } ); } ); } ); |
BDD风格的用例主要使用describe、it来组织厕所代码。describe表示一个测试套件,可以形成多层级的结构,具体到一个测试用例时,使用it。BDD风格提供了 before 、 after 、 beforeEach 、 afterEach 四个钩子方法,用于测试用例的准备、清理工作。前两个方法分别在进入/退出describe时执行,后两个方法则在每一个测试用例执行前/后执行。代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 配合使用BDD风格的断言库shound.js var should = require( 'should' ); describe( 'Array', function () { // 在所有测试开始前的准备工作 before( function () { } ); // 嵌套的describe describe( '#indexOf()', function () { // 一个测试用例 it( 'should return -1 when not present', function () { [ 1, 2, 3 ].indexOf( 4 ).should.equal( -1 ); } ); } ); } ); |
Mocha支持与多个断言库配合,除了Node.js自带的assert模块以外,你还可以使用should.js、better-assert等库。
该断言库扩展了Object.prototype对象,为其添加了一个不可枚举的getter,这样你就可以使用任意对象的should属性来进行断言操作了。should.js支持现代浏览器以及IE8+版本。执行下面的命令添加为当前工程的依赖:
1 |
npm install should --save-dev |
1 2 3 4 5 6 |
// 将should作为属性使用 var should = require('should'); (5).should.be.exactly(5).and.be.a.Number(); // 将should作为函数使用 var should = require('should/as-function'); should(10).be.exactly(5).and.be.a.Number(); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
var user = { name: 'tj', pets: [ 'tobi', 'loki', 'jane', 'bandit' ] }; user.should.have.property( 'name', 'tj' ); user.should.have.property( 'pets' ).with.lengthOf( 4 ); (5).should.be.exactly( 5 ).and.be.a.Number(); should( null ).not.be.ok(); should( 10 ).be.exactly( 10 ); someAsyncTask( foo, function ( err, result ) { should.not.exist( err ); should.exist( result ); result.bar.should.equal( foo ); } ); |
可以看到,这种BDD风格的与语法非常接近自然语言。
should.js的每个断言,其返回值是被包装过的对象,支持链式的断言调用。属性: an, .of, .a, .and, .be, .have, .with, .is, .which 可以随意出现在链条中,但是仅仅增强可读性,不具有任何作用。
几乎全部断言返回相同的对象,除了.length、.property等少数例外,它们把断言对象转移到原对象的属性上。
更多用法参考should.js API。
对异步代码进行单元测试非常简单,你只需要为it提供带有一个入参的回调函数,在其中执行异步操作即可。当异步操作执行完毕,你需要调用Mocha为前述回调传递的done,通知Mocha异步操作已经完毕:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
describe( 'User', function () { describe( '#save()', function () { it( 'should save without error', function ( done ) { // 在这里进行异步操作 var user = new User( 'Luna' ); user.save( function ( err ) { // 异步操作的回调函数 // 在这里调用done通知Mocha异步操作已经完成 if ( err ) done( err ); else done(); } ); } ); } ); } ); |
你可能注意到,done函数接受一个error作为入参,如果你的异步操作的回调函数也是这种风格,上述代码可以简化为:
1 2 3 4 5 6 7 8 |
describe( 'User', function () { describe( '#save()', function () { it( 'should save without error', function ( done ) { var user = new User( 'Luna' ); user.save( done ); } ); } ); } ); |
对于返回Promise的函数,可以这样断言:
1 2 3 |
// find必须返回Promise // eventually创建一个在Promise.then中执行的断言 return db.find({ type: 'User' }).should.eventually.have.length(3); |
由于箭头函数使用词法的this绑定,导致它没有办法正常访问Mocha的上下文,因此不推荐使用。
前面的章节中已经介绍过钩子,需要了解的是,钩子也可以是异步的:
1 2 3 4 5 6 |
beforeEach( function ( done ) { db.clear( function ( err ) { if ( err ) return done( err ); db.save( [ tobi, loki, jane ], done ); } ); } ); |
钩子方法可以定义在任何describe的外部,称为根级别钩子, 这种钩子会在任意用例的前后执行。
你可以指定让失败的测试重复指定的次数,通常用于端到端测试,在单元测试中一般不使用。
1 2 3 4 |
describe( 'retries', function () { // 最多重复所有测试用例4次 this.retries( 4 ); } ); |
很多报告方式支持显式测试消耗的时间,连同标记一个用例“执行缓慢”。是否缓慢的阈值在测试套件中指定:
1 2 3 4 |
describe( 'retries', function () { // 10秒被认为执行缓慢 this.slow(10000); } ); |
你可以在测试套件、测试用例级别设置测试用例执行的超时时间,内部嵌套的套件、用例会继承该设置:
1 2 3 |
describe('a suite of tests', function() { this.timeout( 500 ); } |
在钩子中也可以进行超时控制,调用 this.timeout(0) 可以禁用超时控制。
Mocha提供了一个命令行工具,调用格式为:
1 |
mocha [debug] [options] [files] |
选项 | 说明 | ||
-R, --reporter | 指定使用的报告器 | ||
-b, --bail | 在第一个失败后退出 | ||
-S, --sort | 排序测试文件 | ||
-d, --debug | 启用Node.js的 --debug选项 | ||
-g, --grep | 仅运行匹配正则式的测试文件 | ||
-f, --fgrep | 仅运行匹配文件名的测试文件 | ||
-i, --invert | 反转上面两个选项的效果 | ||
-r, --require |
导入一个模块 如果你在.js扩展名的文件中编写ES6,需要:
然后使用 mocha --require babel-register 选项调用。--compilers选项仅仅在使用其它扩展名编写ES6时才需要 |
||
--compilers |
以<ext>:<module>的形式指定脚本编译器。 |
||
-s, --slow | 判定执行缓慢的阈值 | ||
-t, --timeout | 测试用例执行超时的阈值 | ||
-u, --ui | 指定用户接口(测试风格),可选值:bdd tdd qunit exports | ||
-w, --watch | 监控当前目录的文件变动,一旦变化即测试 | ||
--check-leaks | 检测全局变量泄漏 | ||
--globals | 允许指定的全局变量,逗号分隔 | ||
--full-trace | 打印完整调用栈 | ||
--es_staging | 启用说用staged特性 | ||
--prof | 记录统计性的剖析信息 | ||
--recursive | 包含子目录中的测试文件 | ||
--reporters | 显示可用的报告器 | ||
--retries | 失败用例重试次数 | ||
--use_strict | 启用严格模式 |
Leave a Reply