mocha是一个运行在Node和浏览器中的功能非常强大并易于异步测试的框架。它串行执行,并支持灵活精确的报告,将未捕获的异常映射到正确的测试用例中。
安装
- 全局安装
$npm install -g mocha
- 作为项目开发依赖安装
$npm install --save-dev mocha
入门
$mkdir test
$vim test/test.js
在vim中编辑:
var assert = require('assert');
describe('Array', function() {
describe('#indexOf()', function() {
it('should return -1 when the value is not present', function() {
assert.equal(-1, [1,2,3].indexOf(4));
});
});
});
在terminal中执行:
$./node_modules/mocha/bin/mocha
Array
#indexOf() ✓
should return -1 when the value is not present
1 passing (9ms)
在package.json中设置测试脚本:
"scripts": {
"test": "mocha"
}
运行test:
$npm test
异步代码
使用mocha测试异步代码相当简单,只需要在it()中添加一个callback(通常我们命名为done),mocha便会在测试时等待这个函数来完成测试。
describe('User', function() {
describe('#save()', function() {
it('should save without error', function(done) {
var user = new User('Luna');
user.save(done);
});
});
});
Promise
mocha不仅可以使用done回调,还可以返回一个promise。
beforeEach(function() {
return db.clear()
.then(function() {
return db.save([tobi, loki, jane]);
});
});
describe('#find()', function() {
it('respond with matching records', function() {
return db.find({ type: 'User' }).should.eventually.have.length(3);
});
});
同步代码
测试同步代码时,没有回调函数,mocha会自动继续执行下一个测试。
describe('Array', function() {
describe('#indexOf()', function() {
it('should return -1 when the value is not present', function() {
[1,2,3].indexOf(5).should.equal(-1);
[1,2,3].indexOf(0).should.equal(-1);
});
});
});
钩子(HOOKS)
默认接口风格为“BDD”,因此mocha提供了before(),after(),beforeEach(),afterEach()
四个钩子方法。这几个方法可以用来设置先决条件或清除测试条件。
describe('hooks', function() {
before(function() {
// runs before all tests in this block
});
after(function() {
// runs after all tests in this block
});
beforeEach(function() {
// runs before each test in this block
});
afterEach(function() {
// runs after each test in this block
});
// test cases
});
测试代码可以散布在任意位置,但执行顺序为:
before() > beforeEach() > Tests > afterEach() > after()
Describing Hooks
所有的钩子都可以指定一个description选项运行,以使得mocha可以在运行时更容易地指出错误,如果钩子是一个给定名称的函数,那么将会使用函数名。
beforeEach(function namedFun() {
// beforeEach:namedFun
});
beforeEach('some description', function() {
// beforeEach:some description
});
异步钩子
所有的钩子可以使同步的也可以使异步的。
describe('Connection', function() {
var db = new Connection,
tobi = new User('tobi'),
loki = new User('loki'),
jane = new User('jane');
beforeEach(function(done) {
db.clear(function(err) {
if (err) return done(err);
db.save([tobi, loki, jane], done);
});
});
describe('#find()', function() {
it('respond with matching records', function(done) {
db.find({type: 'User'}, function(err, res) {
if (err) return done(err);
res.should.have.length(3);
done();
});
});
});
});
Pending测试
describe('Array', function() {
describe('#indexOf()', function() {
// pending test below it('should return -1 when the value is not present');
});
});
Exclusive测试
Exclusive通过为函数加上 .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
});
});
});
如果出现钩子,那么它依然会被执行
Inclusive测试
与Exclusive相反,使用 .skip 会让mocha忽略一组测试用例。
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
});
});
});
Retry测试
可以指定次数让失败的测试重试。主要用于端对端测试,不要用于单元测试。
重试会重新执行beforeEach/afterEach 钩子,但不会执行before/after**。
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;
});
});
动态生成测试
使用 Function.prototype.call 和函数表达式动态生成测试集。
var assert = require('chai').assert;
function add() {
return Array.prototype.slice.call(arguments).reduce(function(prev, curr) {
return prev + curr;
}, 0);
}
describe('add()', function() {
var tests = [
{args: [1, 2], expected: 3},
{args: [1, 2, 3], expected: 6},
{args: [1, 2, 3, 4], expected: 10}
];
tests.forEach(function(test) {
it('correctly adds ' + test.args.length + ' args', function() {
var res = add.apply(null, test.args);
assert.equal(res, test.expected);
});
});
});
得到如下的输出:
$ mocha
add()
✓ correctly adds 2 args
✓ correctly adds 3 args
✓ correctly adds 4 args
Test Duration
mocha会在执行过程中展示执行周期,对于slow的测试用例,可以使用slow()方法调整。
describe('something slow', function() {
this.slow(10000);
it('should take long enough for me to go make a sandwich', function() {
// ...
});
});
Timeouts
Suite-Level
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);
});
})
Test-Level
it('should take less than 500ms', function(done){
this.timeout(500);
setTimeout(done, 300);
});
Hook-Level
describe('a suite of tests', function() {
beforeEach(function(done) {
this.timeout(3000); // A very long environment setup.
setTimeout(done, 2500);
});
});
使用this.timeout(0)禁用所有timeout**