Mocha中文指南

mocha是一款比较流行的测试框架,出自TJ之手,跟jasmine相比,它有灵活的断言语法,测试提示也比较友好,其它方面跟jasmine类似.

使用条件

npm install -g mocha

mocha *.js

mocha跟jasmine一个显著区别在于,它的断言库不是固定的,支持nodejs自带的assert库,should.js,expect.js,chai,better-assert,然后也支持BDD语法的describe与it.

因为should.js也是TJ写的,所以这里重点介绍它的断言语法,更多它的API使用文档,可以点击这里

should.js

下面重点介绍它的一些常用手法,测试环境可以使用mocha

先说下,should.js的一个特点,就是它支持友好语法的链式调用,这些语法其实什么都没做,只是编写比较友好,方便阅读,常见的语法有下面这些

be,an,of,a,and,have,with,is,which,the,在should后面加上not代表相反的意思.

结合比较操作方法,看看下面一个简单的例子

require('should');

describe('test should.js', function(){

it('test chain', function(){

(10).should.is.be.the.eql(10);

});

});

上面例子中的is,be,the其实没有顺序要求,读起来怎么友好就怎么写,因为它们什么都没做,只是返回should.js包装函数.

ok

检查期望的值能否转换成`true`

(true).should.be.ok;

true | True

检查期望的值是否为`true`,不转换

(true).should.be.true;

false.should.not.be.True;

false | False

检查期望的值是否为`false`,不转换

(true).should.not.be.false;

false.should.be.False;

eql

检查期望的值跟真实的值在字面上是否相等,并且深度比较

require('should');

describe('test should.js', function(){

var foo = {

foo: 'foo',

bar: {

bar: 'bar'

}

};

it('test eql', function(){

(foo).should.be.eql({

foo: 'foo',

bar: {

bar: 'bar'

}

});

});

});

equal | exactly

检查期望的值与真实的值是一样的,当是比较值类型的话,跟`eql`一样,比较引用类型的话,

则要检查两者是否引用同一地址.

require('should');

describe('test should.js', function(){

var foo = {

foo: 'foo',

bar: {

bar: 'bar'

}

};

it('test eql', function(){

(foo).should.not.be.equal({

foo: 'foo',

bar: {

bar: 'bar'

}

});

});

});

throw | throwError

检查期望的函数是否会返回异常,方法参数支持异常信息,正则表达式,对象,以便精确匹配错误信息

(function(){ throw new Error('fail') }).should.throw();

(function(){ throw new Error('fail') }).should.throw('fail');

(function(){ throw new Error('fail') }).should.throw(/fail/);

(function(){ throw new Error('fail') }).should.throw(Error);

var error = new Error();

error.a = 10;

(function(){ throw error; }).should.throw(Error, { a: 10 });

(function(){ throw error; }).should.throw({ a: 10 });

match

检查期望的值与传入的`正则`,`函数`,`对象`进行匹配

匹配规则如下:

如果参数是正则并且期望值是字符串的话,则直接正则匹配字符串即可.

如果参数是正则并且期望值是数组的话,则依次用正则匹配数组元素.

如果参数是正则并且期望值是对象,则依次对对象键值用正则匹配.

如果参数是函数,当函数抛异常或者返回false,则判定为没匹配上.

如果参数是对象,则相同键值用上面的规则来匹配.

其它情况都适为没匹配上.

'foobar'.should.match(/^foo/);

'foobar'.should.not.match(/^bar/);

({ a: 'foo', c: 'barfoo' }).should.match(/foo$/);

['a', 'b', 'c'].should.match(/[a-z]/);

(5).should.not.match(function(n) {

return n < 0;

});

(5).should.not.match(function(it) {

it.should.be.an.Array;

});

({ a: 10, b: 'abc', c: { d: 10 }, d: 0 }).should

.match({ a: 10, b: /c$/, c: function(it) {

return it.should.have.property('d', 10);

}});

[10, 'abc', { d: 10 }, 0].should

.match({ '0': 10, '1': /c$/, '2': function(it) {

return it.should.have.property('d', 10);

}});

matchEach

依次对期望值进行匹配

匹配规则如下:

如果参数是正则,则依次对期望值中的对象值或者数组项进行正则匹配

如果参数是函数,当函数抛异常或者返回false,则没匹配上

其它情况,则直接按eql来处理

[ 'a', 'b', 'c'].should.matchEach(/\w+/);

[ 'a', 'a', 'a'].should.matchEach('a');

[ 'a', 'a', 'a'].should.matchEach(function(value) { value.should.be.eql('a') });

{ a: 'a', b: 'a', c: 'a' }.should.matchEach(function(value) { value.should.be.eql('a') });

Infinity

检查期望的值是否为无穷大或者无穷小

(10).should.not.be.Infinity;

NaN.should.not.be.Infinity;

NaN

检查期望的值是否为NaN

(10).should.not.be.NaN;

NaN.should.be.NaN;

above | greaterThan

检查期望的值是否大于某数

(10).should.be.above(0);

(10).should.not.be.greaterThan(100);

approximately

检查期望的值大约在(某个数±某个半径)内.

// 9.99 10±0.1

(9.99).should.be.approximately(10, 0.1);

below | lessThan

检查期望的值小于某数

(0).should.be.below(10);

(100).should.not.be.lessThan(10);

within

检查期望的值在某两个数之前,包含两个数

(10).should.be.within(10, 20);

(13).should.be.within(10, 15);

empty

检查期望的值是否为空,比如空字符串,空数组,空对象.

''.should.be.empty;

[].should.be.empty;

({}).should.be.empty;

enumerable

检查期望的值是否有可枚举的属性

({ a: 10 }).should.have.enumerable('a');

enumerables

检查期望的值是否有多个可枚举的属性

({ a: 10, b: 10 }).should.have.enumerables('a', 'b');

({ a: 10, b: 10 }).should.have.enumerables(['a', 'b']);

keys | key

检查期望的值是否包含传入的键

({ a: 10 }).should.have.keys('a');

({ a: 10, b: 20 }).should.have.keys('a', 'b');

({ a: 10, b: 20 }).should.have.keys([ 'a', 'b' ]);

({}).should.have.keys();

length | lengthOf

检查期望的值的长度

[1, 2].should.have.length(2);

ownProperty

检查期望的值是否有自己的某个属性

({ a: 10 }).should.have.ownProperty('a');

properties

检查期望的值是否有某些属性,可以批量检查属性

({ a: 10 }).should.have.properties('a');

({ a: 10, b: 20 }).should.have.properties([ 'a' ]);

({ a: 10, b: 20 }).should.have.properties({ b: 20 });

property

检查期望的值是否有某个属性,单个检查

({ a: 10 }).should.have.property('a');

({ a: 10 }).should.have.property('a', 10);

propertyByPath

根据传入的参数深度来获取属性的值

({ a: {b: 10}}).should.have.propertyByPath('a', 'b').eql(10);

propertyWithDescriptor

检查期望的值的属性有某些描述

({ a: 10 }).should.have.propertyWithDescriptor('a', { enumerable: true });

startWith

检查字符串是否以某个传入的参数开头

'abc'.should.startWith('a');

endWith

检查字符串是否以某个传入的参数结尾

'abc'.should.endWith('c');

instanceof | instanceOf

检查期望的值是否是某个类的实例

'abc'.should.be.instanceof(String);

type

检查期望的值是否是某个类型

'abc'.should.be.type('string');

null | Null

检查期望的值是否为null

var should = require('should');

describe('test should.js ', function(){

it('test null ', function(){

should(null).be.null;

});

});

undefined | Undefined

检查期望的值是否undefined

var should = require('should');

describe('test should.js ', function(){

it('test undefined', function(){

var a;

should(a).be.undefined;

});

});

上面是一些常用的should.js中的断言方法,下面简单的说下mocha测试框架的用法

异步处理与前后注入

跟jasmine类似,也是通过在it,beforeEach里传入done来确定是否执行完成

describe('test should.js', function(){

var foo = 0;

before('首次调用',function(done){

setTimeout(function(){

foo += 1;

done()

}, 1000);

});

beforeEach(function(done){

setTimeout(function(){

foo += 1;

done();

}, 1000);

})

afterEach(function(){

foo = 0;

});

it('test beforeEach', function(done){

setTimeout(function(){

(foo).should.eql(2);

done();

}, 1000);

})

});

禁用与开启测试

.only可以让某个it执行而忽略别的it

describe('1.test mocha', function(){

it.only('test .only', function(){

'123'.should.be.String;

});

// 下面的spec不会执行

it('ignore invoke', function(){

(0).should.be.eql(0);

});

});

.skip可以禁止某个it而执行别的it

describe('test mocha', function(){

// 下面的spec不会执行

it.skip('ignore spec', function(){

({}).should.be.Object;

});

it('test .skip', function(){

({}).should.be.empty;

});

});

自由切换bdd,tdd,exports模式

mocha -u [bdd | tdd | exports] *.js

-u选项支持传递要使用的测试类型,默认是bdd,可以选择tdd,exports

BDD

bdd用的比较多,jasmine的测试风格就是bdd,它的特征就是使用describe,it

describe('Array', function(){

before(function(){

// ...

});

describe('#indexOf()', function(){

it('should return -1 when not present', function(){

[1,2,3].indexOf(4).should.equal(-1);

});

});

});

TDD

tdd跟bdd区别在于,它使用suite,test,suiteSetup,suiteTeardown,setup,teardown

suite('Array', function(){

setup(function(){

// ...

});

suite('#indexOf()', function(){

test('should return -1 when not present', function(){

([1,2,3].indexOf(4)).should.be.eql(-1);

});

});

});

Exports

exports类似于node里的模块语法,before, after, beforeEach, and afterEach是作为对象的属性来处理,其它对象的值默认是suite,属性是函数的话,代表是一个test

module.exports = {

before: function(){

// ...

},

'Array': {

'#indexOf()': {

'should return -1 when not present': function(){

[1,2,3].indexOf(4).should.equal(-1);

}

}

}

};

其实的测试风格还有QUnit,Require,更多详情请点击这里.

自由切换输出风格

目前默认的输出格式为spec,可以通用-R spec来指定,目前已有的格式有dot,nyan,tap,list,progress,json,min,doc,markdown等,html格式只在浏览器中有效

mocha细节问题

设置测试组超时时间,可以在describe或者suite代码块里调用this.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, 200);

})

})

设置测试用例超时时间,可以在it或者test代码块里调用this.timeout方法

it('should take less than 500ms', function(done){

this.timeout(500);

setTimeout(done, 300);

})

mocha默认会执行./test/*.js里的测试文件,所以这个目录是放测试文件的好地方

为了方便执行mocha命令,可以建立一个makefile文件,如下

test:

./node_modules/.bin/mocha --reporter list

.PHONY: test

下次运行的话,直接在终端上输入make test

总结

mocha是一个功能比较丰富的测试框架,希望更多的前端工作者们能用上它.

随便看看