NodeJS测试框架mocha入门教程
NodeJS里最常用的测试框架估计就是mocha了。它支持多种node的assertlibs,同时支持异步和同步的测试,同时支持多种方式导出结果,也支持直接在browser上跑Javascript代码测试。
本文示例大多源于官网示例,部分示例结合需要或自己的感想有所改动。更多介绍请看官方网址:MochaonGithub
Installation:
当你成功安装nodejsv0.10和npm后执行下面这条命令。
#npminstall-gmocha
p.s.Ubuntu的注意apt源里的nodejs版本会比较旧,某些module会不支持,请从nodejs官网进行源码安装。
FirststeptoMocha:
以下为最简单的一个mocha示例:
varassert=require("assert"); describe('Array',function(){ describe('#indexOf()',function(){ it('shouldreturn-1whenthevalueisnotpresent',function(){ assert.equal(-1,[1,2,3].indexOf(5)); assert.equal(-1,[1,2,3].indexOf(0)); }) }) });
describe(moduleName,testDetails)由上述代码可看出,describe是可以嵌套的,比如上述代码嵌套的两个describe就可以理解成测试人员希望测试Array模块下的#indexOf()子模块。module_name是可以随便取的,关键是要让人读明白就好。
it(info,function)具体的测试语句会放在it的回调函数里,一般来说info字符串会写期望的正确输出的简要一句话文字说明。当该itblock内的testfailed的时候控制台就会把详细信息打印出来。一般是从最外层的describe的module_name开始输出(可以理解成沿着路径或者递归链或者回调链),最后输出info,表示该期望的info内容没有被满足。一个it对应一个实际的testcase
assert.equal(exp1,exp2)断言判断exp1结果是否等于exp2,这里采取的等于判断是==而并非===。即assert.equal(1,‘1')认为是True。这只是nodejs里的assert.js的一种断言形式,下文会提到同样比较常用的should.js。
如果exp1和exp2均为字符串,字符串比较出错时则控制台会用颜色把相异的部分标出来。
Asynchronous
Friststep中的代码显然是个Synchronous的代码,那么对于异步代码应该怎么做呢?很简单,在你最深处的回调函数中加done()表示结束。
fs=require('fs'); describe('File',function(){ describe('#readFile()',function(){ it('shouldreadtest.lswithouterror',function(done){ fs.readFile('test.ls',function(err){ if(err)throwerr; done(); }); }) }) })
done()
按照瀑布流编程习惯,取名done是表示你回调的最深处,也就是结束写嵌套回调函数。但对于回调链来说done实际上意味着告诉mocha从此处开始测试,一层层回调回去。
上例代码是testpass的,我们尝试把test.ls改成不存在的test.as。便会返回具体的错误位置。
这里可能会有个疑问,假如我有两个异步函数(两条分叉的回调链),那我应该在哪里加done()呢?实际上这个时候就不应该在一个it里面存在两个要测试的函数,事实上一个it里面只能调用一次done,当你调用多次done的话mocha会抛出错误。所以应该类似这样:
fs=require('fs'); describe('File',function(){ describe('#readFile()',function(){ it('shouldreadtest.lswithouterror',function(done){ fs.readFile('test.ls',function(err){ if(err)throwerr; done(); }); }) it('shouldreadtest.jswithouterror',function(done){ fs.readFile('test.js',function(err){ if(err)throwerr; done(); }); }) }) })
Pending
即省去测试细节只保留函数体。一般适用情况比如负责测试框架的写好框架让组员去实现细节,或者测试细节尚未完全正确实现先注释以免影响全局测试情况。这种时候mocha会默认该测试pass。
作用有点像Python的pass。
describe('Array',function(){ describe('#indexOf()',function(){ it('shouldreturn-1whenthevalueisnotpresent',function(){ }) }) });
Exclusive&&Inclusive
其实很好理解,分别对应only和skip函数。
fs=require('fs'); describe('File',function(){ describe('#readFile()',function(){ it.skip('shouldreadtest.lswithouterror',function(done){ fs.readFile('test.ls',function(err){ if(err)throwerr; done(); }); }) it('shouldreadtest.jswithouterror',function(done){ }) }) })
上面的代码只会有一个testcomplete,只有only的会被执行,另一个会被忽略掉。每个函数里只能有一个only。如果是it.skip,那么该case就会被忽略。
only和skip共用没有什么实际意义,因为only的作用会把skip屏蔽掉。
fs=require('fs'); describe('File',function(){ describe('#readFile()',function(){ it.skip('shouldreadtest.lswithouterror',function(done){ fs.readFile('test.as',function(err){ if(err)throwerr; done(); }); }) it('shouldreadtest.jswithouterror',function(done){ }) }) })
上面的代码尽管test.as不存在,但是由于skip,依然会显示testcomplete。
Before&&After
单元测试里经常会用到before和after。mocha同时还提供了beforeEach()和afterEach()。
这里为方便阅读用livescript表示,!->可理解成function(){}。细节无需细读,只需通过框架了解这几个函数如何使用便可。
require!assert require!fs can=it describe'Array',!-> beforeEach!-> console.log'beforeEachArray' before!-> console.log'beforeArray' before!-> console.log'beforeArraysecondtime' after!-> console.log'afterArray' describe'#indexOf()',!-> can'shouldreturn-1whenthevalueisnotpresent',!-> assert.equal-1,[1,2,3].indexOf0 can'shouldreturn1whenthevalueisnotpresent',!-> describe'File',!-> beforeEach!-> console.log'beforeEachfiletest!' afterEach!-> console.log'afterEachFiletest!' describe'#readFile()',!-> can'shouldreadtest.lswithouterror',!(done)-> fs.readFile'test.ls',!(err)-> iferr throwerr done! can'shouldreadtest.jswithouterror',!(done)-> fs.readFile'test.js',!(err)-> iferr throwerr done!
由结果可知(after的使用与before同理),
beforeEach会对当前describe下的所有子case生效。
before和after的代码没有特殊顺序要求。
同一个describe下可以有多个before,执行顺序与代码顺序相同。
同一个describe下的执行顺序为before,beforeEach,afterEach,after
当一个it有多个before的时候,执行顺序从最外围的describe的before开始,其余同理。
TestDrivenDevelop(TDD)
mocha默认的模式是BehaviorDrivenDevelop(BDD),要想执行TDD的test的时候需要加上参数,如
mocha-utddtest.js
前文所讲的describe,it,before,after等都属于BDD的范畴,对于TDD,我们用suite,test,setup,teardown。样例代码如下:
suite'Array',!-> setup!-> console.log'setup' teardown!-> console.log'teardown' suite'#indexOf()',!-> test'shouldreturn-1whennotpresent',!-> assert.equal-1,[1,2,3].indexOf4