mocha使用指南

概述

mocha 是一款可运行在 node 环境或浏览器上的测试框架。

mocha 本身没有实现断言库,可使用 chai, should.js, expect.js, better-assert, unexpected 等断言库或 node 内置的 assert 模块。断言库错误输出需有 actual, expected 属性。

示例

BDD

1
2
3
4
5
6
7
8
9
// BDD 风格,describe/context, it/specify, before, after, beforeEach, afterEach
var assert = require('assert');
describe('Array', function() {// 测试套件
describe('#indexOf()', function() {
it('should return -1 when the value is not present', function() {// 测试单元
assert.equal([1,2,3].indexOf(4), -1);
});
});
});

TDD

1
2
3
4
5
6
7
8
9
10
11
12
// TDD 风格,suite, test, suiteSetup, suiteTeardown, setup, teardown
suite('Array', function() {
setup(function() {
// ...
});

suite('#indexOf()', function() {
test('should return -1 when not present', function() {
assert.equal(-1, [1,2,3].indexOf(4));
});
});
});

EXPORTS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// EXPORTS 风格,before, after, beforeEach, afterEach
module.exports = {
before: function() {
// ...
},

'Array': {// 对象作为测试套件
'#indexOf()': {
'should return -1 when not present': function() {// 函数为测试单元
[1,2,3].indexOf(4).should.equal(-1);
}
}
}
};

QUNIT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// QUNIT 风格,suite, test, before, after, beforeEach, afterEach
function ok(expr, msg) {
if (!expr) throw new Error(msg);
}

suite('Array');

test('#length', function() {
var arr = [1,2,3];
ok(arr.length == 3);
});

test('#indexOf()', function() {
var arr = [1,2,3];
ok(arr.indexOf(1) == 0);
ok(arr.indexOf(2) == 1);
ok(arr.indexOf(3) == 2);
});

suite('String');

test('#length', function() {
ok('foo'.length == 3);
});

REQUIRE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// REQUIRE 风格,使用 require 注入
var testCase = require('mocha').describe;
var pre = require('mocha').before;
var assertions = require('mocha').it;
var assert = require('chai').assert;

testCase('Array', function() {
pre(function() {
// ...
});

testCase('#indexOf()', function() {
assertions('should return -1 when not present', function() {
assert.equal([1,2,3].indexOf(4), -1);
});
});
})

配置

mocha 后跟测试文件名(可使用通配符),或将测试脚本放在 test 目录里,执行 mocha 命令测试 test 目录下的测试脚本(默认只执行第一层)。浏览器端使用 mocha.setup 方法配置 mocha。

选项(可以将命令行参数放在 mocha.opts 文件里,也可以 mocha.opts 文件里指定测试目录):

  • -u, –ui 测试脚本编码风格,可选值 bdd|tdd|qunit|exports。
  • –recursive 使用 mocha 测试 test 目录下所有文件。
  • -g, –grep 只测试匹配正则的 it 。
  • -f, –fgrep 只测试包含字符串的 it。
  • -i, –invert 反转 grep, fgrep 选项。
  • –bail, -b 有一个测试脚本未通过时,就停止测试。
  • -d, –debug 启动 debug 模式。
  • –debug-brk enable node’s debugger breaking on the first line???
  • -gc, –expose-gc expose gc extension???
  • –harmony<_classes,_generators,…> all node –harmony* flags are available???
  • –es_staging 启用所有 staged 特征???
  • -S, –sort 排序测试文件。
  • –compilers :,… 指定测编译器,如 mocha –compilers js:babel-core/register。若需使用 Map、Set 等,须在测试脚本前 import ‘babel-polyfill’。
  • -r, –require 加载特定的模块,如 ‘babel-polyfill’。
  • –file 测试时加载指定文件。
  • –globals 以 ‘,’ 分割形式注入全局变量。
  • -A, –async-only 测试脚本只能使用异步编程,回调或 promise 形式。
  • -w, –watch 监视文件变动,自动运行测试脚本。
  • -t, –timeout 指定测试时的超时时间,默认为 2000 ms。
  • -s, –slow 高亮显示超过指定时间的测试报告,默认为 75 ms。
  • –check-leaks 检测全局变量泄漏。
  • –growl, -G 将报告显示在桌面。
  • -R, –reporter 指定报告打印形式,默认是 spec 格式,可选值 tap, dot, nyan, mochawesome 网页报告(须先安装 npm install –dev mochawesome)。
  • -O, –reporter-options <k=v,k2=v2,…>,打印选项。
  • –reporters 显示所有报告格式。
  • -c, –colors 显示颜色。
  • -C, –no-colors 不显示颜色。
  • –full-trace 显示完整的堆栈信息。
  • 生成规格文件,如 mocha –recursive -R markdown > spec.md 或 mocha –recursive -R doc > spec.html。

特性

钩子函数

  • before,在测试用例之前执行
  • after,在测试用例之后执行
  • beforeEach,在每个单元测试前执行
  • afterEach,在每个单元测试后执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 钩子允许在 describe 外围,回调将在测试脚本之前或之后执行
beforeEach(function() {
console.log('before every test in every file');
});

describe('hooks', function() {

// 钩子函数以匿名函数使用,允许携带描述;命名函数不能
before('some description', function() {
// runs before all tests in this block
});

// 钩子支持同步或异步编程
beforeEach(function(done) {
db.clear(function(err) {
if (err) return done(err);
db.save([tobi, loki, jane], done);
});
});

// test cases
});

异步测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 回调函数形式
describe('User', function() {
describe('#save()', function() {
it('should save without error', function(done) {// done 只能执行一次,两次及以上会报错
var user = new User('Luna');
user.save(done);// done 能自动识别并处理 err 错误
});
});
});

// promise 形式
describe('#find()', function() {
it('respond with matching records', function() {
// db.find({ type: 'User' }) 返回 promise
return db.find({ type: 'User' }).should.eventually.have.length(3);
});
});

// async 函数形式
describe('#find()', function() {
it('responds with matching records', async function() {
const users = await db.find({ type: 'User' });
users.should.have.length(3);
});
});

延迟执行

命令行选项 –delay 用于延迟,相应测试脚本使用 setTimeout 包裹。

1
2
3
4
5
6
7
8
9
setTimeout(function() {
// do some setup

describe('my suite', function() {
// ...
});

run();
}, 5000);

搁置测试

使测试处于 pending 状态,仍然会打印报告。

1
2
3
4
5
6
describe('Array', function() {
describe('#indexOf()', function() {
// pending test below
it('should return -1 when the value is not present');
});
});

限制测试

  • describe, it 调用 only 方法将只运行指定测试脚本,添加的钩子仍会执行。
  • describe, it 调用 skip 方法将避免某些脚本的执行。skip 也可以在 mocha 运行过程中调用,或在钩子中调用,两者均使用 this.skip()。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// only 方法限制只执行某些测试脚本
describe('Array', function() {
describe.only('#indexOf()', function() {
it.only('should return -1 unless present', function() {
// this test will be run
});

it('should return the index when present', function() {
// this test will not be run
});
});
});

// skip 方法跳过执行指定测试脚本
describe('Array', function() {
describe('#indexOf()', function() {
it.skip('should return -1 unless present', function() {
// this test will not be run
});

it('should return the index when present', function() {
// this test will be run
});
});
});

// mocha 运行时 skip
it('should only test in the correct environment', function() {
if (/* check test environment */) {
// make assertions
} else {
this.skip();
}
});

// 钩子 skip
before(function() {
if (/* check test environment */) {
// setup code
} else {
this.skip();
}
});

实例方法

  • retries(num),指定重复执行测试脚本 num 次,不推荐在单元测试中使用。
  • slow(time),高亮显示超过指定时间的测试报告,默认为 75 ms。
  • timeout(time),设定超时时间,可在 describe, it 或钩子 中调用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// retries
describe('retries', function() {
// Retry all tests in this suite up to 4 times
this.retries(4);

beforeEach(function () {
browser.get('http://www.yahoo.com');
});

it('should succeed on the 3rd try', function () {
// Specify this test to only retry up to 2 times
this.retries(2);
expect($('.foo').isDisplayed()).to.eventually.be.true;
});
});

// slow
describe('something slow', function() {
this.slow(10000);

it('should take long enough for me to go make a sandwich', function() {
// ...
});
});

// timeout
describe('a suite of tests', function() {
this.timeout(500);

it('should take less than 500ms', function(done){
setTimeout(done, 300);
});

it('should take less than 500ms as well', function(done){
setTimeout(done, 250);
});
})