NodeJs測試框架Mocha的安裝與使用
Mocha是運(yùn)行在nodejs和瀏覽器下的JavaScript的單元測試框架,官方文檔在https://mochajs.org/,相當(dāng)?shù)娜菀咨鲜趾秃糜?,單元測試框架其實(shí)都差不多,基本都包含下面內(nèi)容:
用于寫測試用例的宏,屬性或者函數(shù)
斷定庫, 用于測試是否可以通過
輔助庫,如hook庫(測試前后調(diào)用某些函數(shù)或者方法),異常檢查(某些函數(shù)在某些參數(shù)的情況下拋出異常), 輸入組合(支持多排列的參數(shù)輸入組合)等。
支持IDE的集成
下面就按照官方文檔的順序來簡明扼要的
安裝與初步的使用
在控制臺(tái)窗口中執(zhí)行下列命令:
$ npm install -g mocha $ mkdir test $ $EDITOR test/test.js
可以寫如下代碼:
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(5));
assert.equal(-1, [1,2,3].indexOf(0));
});
});
});
回到控制臺(tái):
$ mocha . ✔ 1 test complete (1ms)
這里mocha會(huì)查找當(dāng)前文件目錄下test文件夾下的內(nèi)容,自動(dòng)執(zhí)行。
斷定庫
這個(gè)是判定測試用例是否通過,默認(rèn)下可以用nodejs的assert庫,與此同時(shí),Mocha支持我們使用不同的斷定庫,現(xiàn)在可以支持下面的斷定庫,每個(gè)斷定庫的用法有一些差異,自己可以參考相應(yīng)的文檔。
1 should.js(https://github.com/shouldjs/should.js) BDD style shown throughout these docs (BDD模式,本文檔用的都是這個(gè)斷定庫)
2 better-assert(https://github.com/tj/better-assert) c-style self-documenting assert()(C-模型下的斷定庫)
3 expect.js (https://github.com/Automattic/expect.js)expect() style assertions (expect模式的斷定庫)
4 unexpected(http://unexpected.js.org/) the extensible BDD assertion toolkit
5 chai(https://github.com/chaijs) expect(), assert() and should style assertions
同步代碼
同步代碼表示測試的是同步函數(shù),上面的Array相關(guān)的例子代碼就是。這個(gè)比較好理解。
異步代碼
只所以有異步代碼測試,原因是在nodejs上許多異步函數(shù),如下面的代碼中,只有done()函數(shù)執(zhí)行完畢后,該測試用例才算完成
describe('User', function() {
describe('#save()', function() {
it('should save without error', function(done) {
var user = new User('Luna');
user.saveAsync(function(err) {
if (err) throw err;
done(); // 只有執(zhí)行完此函數(shù)后,該測試用例算是完成。
});
});
});
});
詳解describe和it
上面的實(shí)例代碼比較簡單,那么什么是describe和it呢? 大致上,我們可以看出describe應(yīng)該是聲明了一個(gè)TestSuit(測試集合) ,而且測試集合可以嵌套管理,而it聲明定義了一個(gè)具體的測試用例。 以bdd interface為例,具體的源代碼如下:
/**
* Describe a "suite" with the given `title`
* and callback `fn` containing nested suites
* and/or tests.
*/
context.describe = context.context = function(title, fn) {
var suite = Suite.create(suites[0], title);
suite.file = file;
suites.unshift(suite);
fn.call(suite);
suites.shift();
return suite;
};
/**
* Describe a specification or test-case
* with the given `title` and callback `fn`
* acting as a thunk.
*/
context.it = context.specify = function(title, fn) {
var suite = suites[0];
if (suite.pending) {
fn = null;
}
var test = new Test(title, fn);
test.file = file;
suite.addTest(test);
return test;
};
Hooks(鉤子)
實(shí)際上這個(gè)在寫unit test是很常見的功能,就是在執(zhí)行測試用例,測試用例集合前或者后需要某個(gè)回調(diào)函數(shù)(鉤子)。Mocha提供了before(),after(), beforeEach() 和aftetEach(),示例代碼如下:
describe('hooks', function() {
before(function() {
// runs before all tests in this block
// 在執(zhí)行所有的測試用例前 函數(shù)會(huì)被調(diào)用一次
});
after(function() {
// runs after all tests in this block
// 在執(zhí)行完所有的測試用例后 函數(shù)會(huì)被調(diào)用一次
});
beforeEach(function() {
// runs before each test in this block
// 在執(zhí)行每個(gè)測試用例前 函數(shù)會(huì)被調(diào)用一次
});
afterEach(function() {
// runs after each test in this block
// 在執(zhí)行每個(gè)測試用例后 函數(shù)會(huì)被調(diào)用一次
});
// test cases
});
hooks還有下列其他用法:
Describing Hooks - 可以對(duì)鉤子函數(shù)添加描述,能更好的查看問題
Asynchronous Hooks (異步鉤子): 鉤子函數(shù)可以是同步,也可以是異步的,和測試用例一下,下面是異步鉤子的示例代碼:
beforeEach(function(done) {
// 異步函數(shù)
db.clear(function(err) {
if (err) return done(err);
db.save([tobi, loki, jane], done);
});
});
Root-Level Hooks (全局鉤子) - 就是在describe外(測試用例集合外)執(zhí)行,這個(gè)一般是在所有的測試用例前或者后執(zhí)行。
Pending Tests (掛起測試)
就是有一些測試,現(xiàn)在還沒有完成,有點(diǎn)類似TODO, 如下面的代碼:
describe('Array', function() {
describe('#indexOf()', function() {
// pending test below 暫時(shí)不寫回調(diào)函數(shù)
it('should return -1 when the value is not present');
});
});
Exclusive Tests (排它測試)
排它測試就是允許一個(gè)測試集合或者測試用例,只有一個(gè)被執(zhí)行,其他都被跳過。如下面測試用例集合:
describe('Array', function() {
describe.only('#indexOf()', function() {
// ...
});
// 測試集合不會(huì)被執(zhí)行
describe('#ingored()', function() {
// ...
});
});
下面是對(duì)于測試用例:
describe('Array', function() {
describe('#indexOf()', function() {
it.only('should return -1 unless present', function() {
// ...
});
// 測試用例不會(huì)執(zhí)行
it('should return the index when present', function() {
// ...
});
});
});
需要說明的是,對(duì)于Hooks(回調(diào)函數(shù))會(huì)被執(zhí)行。
Inclusive Tests(包含測試)
與only函數(shù)相反,skip函數(shù),將會(huì)讓mocha系統(tǒng)無視當(dāng)前的測試用例集合或者測試用例,所有被skip的測試用例將被報(bào)告為Pending。
下面是對(duì)與測試用例集合的示例代碼:
describe('Array', function() {
//該測試用例會(huì)被ingore掉
describe.skip('#indexOf()', function() {
// ...
});
// 該測試會(huì)被執(zhí)行
describe('#indexOf()', function() {
// ...
});
});
下面例子是對(duì)具體的測試用例:
describe('Array', function() {
describe('#indexOf()', function() {
// 測試用例會(huì)被ingore掉
it.skip('should return -1 unless present', function() {
// ...
});
// 測試用例會(huì)被執(zhí)行
it('should return the index when present', function() {
// ...
});
});
});
Dynamically Generating Tests(動(dòng)態(tài)生成測試用例)
其實(shí)這個(gè)在很多其他的測試工具,如NUnit也會(huì)有,就是將測試用例的參數(shù)用一個(gè)集合代替,從而生成不同的測試用例。下面是具體的例子:
var assert = require('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}
];
// 下面就會(huì)生成三個(gè)不同的測試用例,相當(dāng)于寫了三個(gè)it函數(shù)的測試用例。
tests.forEach(function(test) {
it('correctly adds ' + test.args.length + ' args', function() {
var res = add.apply(null, test.args);
assert.equal(res, test.expected);
});
});
});
Interfaces(接口)
Mocha的接口系統(tǒng)允許用戶用不同風(fēng)格的函數(shù)或者樣式寫他們的測試用例集合和具體的測試用例,mocha有BDD,TDD,Exports,QUnit和Require 風(fēng)格的接口。
BDD - 這個(gè)是mocha的默認(rèn)樣式,我們?cè)诒疚闹械氖纠a就是這樣的格式。
其提供了describe(), context(), it(), before(), after(), beforeEach(), and afterEach()的函數(shù),示例代碼如下:
describe('Array', function() {
before(function() {
// ...
});
describe('#indexOf()', function() {
context('when not present', function() {
it('should not throw an error', function() {
(function() {
[1,2,3].indexOf(4);
}).should.not.throw();
});
it('should return -1', function() {
[1,2,3].indexOf(4).should.equal(-1);
});
});
context('when present', function() {
it('should return the index where the element first appears in the array', function() {
[1,2,3].indexOf(3).should.equal(2);
});
});
});
});
TDD - 提供了 suite(), test(), suiteSetup(), suiteTeardown(), setup(), 和 teardown()的函數(shù),其實(shí)和BDD風(fēng)格的接口類似(suite相當(dāng)于describe,test相當(dāng)于it),示例代碼如下:
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 - 對(duì)象的值都是測試用例集合,函數(shù)值都是測試用例。 關(guān)鍵字before, after, beforeEach, and afterEach 需要特別定義。
具體的示例代碼如下:
module.exports = {
before: function() {
// ...
},
'Array': {
'#indexOf()': {
'should return -1 when not present': function() {
[1,2,3].indexOf(4).should.equal(-1);
}
}
}
};
QUnit - 有點(diǎn)像TDD,用suit和test函數(shù),也包含before(), after(), beforeEach()和afterEach(),但是用法稍微有點(diǎn)不一樣, 可以參考下面的代碼:
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 - 該接口允許我們利用require關(guān)鍵字去重新封裝定義 describe ,it等關(guān)鍵字,這樣可以避免全局變量。
如下列代碼:
var testCase = require('mocha').describe;
var pre = require('mocha').before;
var assertions = require('mocha').it;
var assert = require('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);
});
});
});
上述默認(rèn)的接口是BDD, 如果想使用其他的接口,可以使用下面的命令行:
mocha -ui 接口(TDD|Exports|QUnit...)
Reporters (測試報(bào)告/結(jié)果樣式)
Mocha 支持不同格式的測試結(jié)果暫時(shí),其支持 Spec, Dot Matrix,Nyan,TAP…等等,默認(rèn)的樣式為Spec,如果需要其他的樣式,可以用下列命令行實(shí)現(xiàn):
mocha --reporter 具體的樣式(Dot Matrix|TAP|Nyan...)
Editor Plugins
mocha 能很好的集成到TextMate,Wallaby.js,JetBrains(IntelliJ IDEA, WebStorm) 中,這里就用WebStorm作為例子。 JetBrains提供了NodeJS的plugin讓我們很好的使用mocha和nodeJs。 添加mocha 的相關(guān)的菜單,具體配置過程可以參考https://www.jetbrains.com/webstorm/help/running-mocha-unit-tests.html
這里就可以直接在WebStorm中運(yùn)行,調(diào)試mocha的測試用例了。
相關(guān)文章
使用Node.js實(shí)現(xiàn)ORM的一種思路詳解(圖文)
這篇文章主要介紹了用Node.js實(shí)現(xiàn)ORM的一種思路詳解(圖文),需要的朋友可以參考下2017-10-10
node.js中的events.emitter.removeAllListeners方法使用說明
這篇文章主要介紹了node.js中的events.emitter.removeAllListeners方法使用說明,本文介紹了events.emitter.removeAllListeners 的方法說明、語法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下2014-12-12
Mac OS X 系統(tǒng)下安裝和部署Egret引擎開發(fā)環(huán)境
之前的文章,我們已經(jīng)介紹了Windows 系統(tǒng)下安裝和部署Egret的開發(fā)環(huán)境,那么,這篇文檔中,我們主要介紹在Mac環(huán)境中安裝Egret以及部署2014-09-09
nodejs對(duì)mongodb數(shù)據(jù)庫的增加修刪該查實(shí)例代碼
在本篇文章里小編給大家整理的是一篇關(guān)于nodejs對(duì)mongodb數(shù)據(jù)庫的增加修刪該查實(shí)例代碼,有需要的朋友們可以參考下。2020-01-01
node+koa2+mysql+bootstrap搭建一個(gè)前端論壇
本篇文章通過實(shí)例給大家分享了用node+koa2+mysql+bootstrap搭建一個(gè)前端論壇的步驟,有需要的朋友參考下。2018-05-05
Nodejs-child_process模塊詳細(xì)介紹
Node.js的child進(jìn)程模塊允許創(chuàng)建并行任務(wù),提高應(yīng)用性能,介紹了exec、execFile、spawn、fork等方法,解釋了它們的使用場景和優(yōu)勢,通過子進(jìn)程模塊,可以執(zhí)行外部命令、腳本或創(chuàng)建新的Node.js實(shí)例,感興趣的朋友跟隨小編一起看看吧2024-09-09
nodejs實(shí)現(xiàn)連接mongodb數(shù)據(jù)庫的方法示例
這篇文章主要介紹了nodejs實(shí)現(xiàn)連接mongodb數(shù)據(jù)庫的方法,結(jié)合實(shí)例形式分析了nodejs針對(duì)mongodb數(shù)據(jù)庫的簡單連接、查詢及關(guān)閉等操作技巧,需要的朋友可以參考下2018-03-03
websocket結(jié)合node.js實(shí)現(xiàn)雙向通信的示例代碼
本文主要介紹了websocket結(jié)合node.js實(shí)現(xiàn)雙向通信的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02
node.js實(shí)現(xiàn)pdf與圖片互轉(zhuǎn)代碼示例
因工作需求,記錄一次如何在Node中pdf與圖片互轉(zhuǎn)各種操作,這篇文章主要給大家介紹了關(guān)于node.js實(shí)現(xiàn)pdf與圖片互轉(zhuǎn)的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-04-04

