學習了MOCHA官網的示例,將學習成果記錄一下。【原文+例子:使用mocha測試】javascript
Mocha是一個跑在node和瀏覽器上的javascript測試框架,讓異步測試變得簡單有趣, 並提供靈活精確的報告。java
使用npm全局安裝node
$ npm install --global mocha
$ npm install --global mocha
做爲項目開發依賴安裝linux
$ npm install --save-dev mocha
$ npm install --save-dev mocha
建立測試文件learn-mochagit
$ npm install mocha -g // 全局安裝mocha $ mkdir test // 建立test文件夾 $ touch test.js // 建立test文件
$ npm install mocha -g // 全局安裝mocha $ mkdir test // 建立test文件夾 $ touch test.js // 建立test文件
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); }); }); });
例子中使用了測試集定義函數describe()
和測試用例定義函數it()
,先引入node
的assert
模塊的eaual()
方法用來驗證兩數是否相等:[1,2,3].indexOf(4)
== -1
github
learn-mocha git:(master) ✗ mocha Array #indexOf() ✓ should return -1 when the value is not present 1 passing (7ms)
learn-mocha git:(master) ✗ mocha Array #indexOf() ✓ should return -1 when the value is not present 1 passing (7ms)
在終端輸入mocha
,能夠看到測試用例經過了。chrome
Mocha
的執行會找到當前命令執行目錄下的test
目錄。./test/*.js
是Mocha
尋找的目標。 也能夠在package.json中設置以下設置,就可使用npm test
命令行開啓Mocha
測試數據庫
"scripts": { "test": "mocha" }
Mocha支持各類斷言庫來驗證功能,例如should.js、chai、expect.js、better-assert、unexpected等express
在mocha中測試異步代碼並不容易。經過給it()
加一個回調函數(一般命名爲done),mocha將會知道異步代碼執行以後須要調用done
來表示測試完成。npm
describe('User', function() { describe('#save()', function() { it('should save without error', function(done) { var user = new User('Luna'); user.save(function(err) { if (err) done(err); else done(); }); }); }); });
當done()能夠接受異步代碼錯誤的時候,上面代碼還能夠簡化爲
describe('User', function() { describe('#save()', function() { it('should save without error', function(done) { var user = new User('Luna'); user.save(done); }); }); });
除了使用回調函數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); }); });
若是js環境支持 async/await, 你能夠這樣寫異步測試
beforeEach(async function() { await db.clear(); await db.save([tobi, loki, jane]); }); describe('#find()', function() { it('responds with matching records', async function() { const users = await db.find({ type: 'User' }); users.should.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); }); }); });
不建議在mocha中使用箭頭函數,由於箭頭函數對this的綁定會使測試用例沒法訪問Mocha上下文中的一些方法。
describe('my suite', () => { it('my test with arrow function', () => { // should set the timeout of this test to 1000 ms; instead will fail this.timeout(1000); assert.ok(true); }); }); describe('my suite', function () { it('my test without arrow function', function() { // set the timeout of this test to 1000 ms; passing this.timeout(1000); assert.ok(true); }); });
Mocha提供了四種hooks用來作測試準備和測後清理工做
var assert = require('assert'); describe('hooks', function() { before(function() { console.log('runs before all tests in this block') }); after(function() { console.log('runs after all tests in this block') }); beforeEach(function() { console.log('runs before each test in this block') }); afterEach(function() { console.log('runs after each test in this block') }); it('test 1', function(){ assert.ok(true) }) it('test 2', function(){ assert.ok(true) }) });
➜ learn-mocha git:(master) ✗ mocha test/hooks.js
hooks
runs before all tests in this block runs before each test in this block ✓ test 1 runs after each test in this block runs before each test in this block ✓ test 2 runs after each test in this block runs after all tests in this block 2 passing (8ms)
任何鉤子在回調前都有一個可選的描述,在測試中能更簡單定位到錯誤。若是一個鉤子是命名函數,在沒有描述時,將會使用函數名。
beforeEach(function() { // beforeEach hook }); beforeEach(function namedFun() { // beforeEach:namedFun }); beforeEach('some description', function() { // beforeEach:some description });
全部hooks(before(), after(), beforeEach(), afterEach()) 都有多是同步或者異步,就像一個常規的測試。例如,您可能但願在每一個測試以前填充虛擬內容的數據庫:
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(); }); }); }); });
若是你須要在全部suites
運行以前執行異步操做,你可能會延遲根suite
。用--delay
運行mocha
。這將把一個特殊的回調函數,run()
附加到全局上下文中:
setTimeout(function() { // do some setup describe('my suite', function() { // ... }); run(); }, 5000);
待定測試將包括在測試結果中,而且標記爲pending。未決測試不被認爲是失敗的測試。不添加回調函數callback便可。
describe('#indexOf()', function() { // pending test below it('should return -1 when the value is not present'); }); });
learn-mocha git:(master) ✗ mocha test/pending.js
Array #indexOf() - should return -1 when the value is not present 0 passing (5ms) 1 pending
it()
中沒有回調函數,就會顯示 0 passing 1 pending
能夠經過添加.only()
到describe()
和it()
函數中,來指定測試套件。測試套件和測試用例能夠屢次定義。若是在測試套件和測試用例同時都加上了.only()
的時候,測試用例的執行是優先的。例如suite 2
中,只執行了test case 5
。
const assert = require('assert') describe('suite 1', function () { describe('sub suite 1', function () { it('test case 1', function () { assert(true) }) it('test case 2', function () { assert(true) }) }) describe.only('sub suite 2', function () { it('test case 3', function () { assert(true) }) }) }) describe.only('suite 2', function () { it('test case 4', function () { assert(true) }) it.only('test case 5', function () { assert(true) }) })
➜ learn-mocha git:(master) ✗ mocha test/exclusive.js
suite 1 sub suite 2 ✓ test case 3 suite 2 ✓ test case 5 2 passing (7ms) (5ms)
與 .only()
相反,經過給describe()
和it()
加上.skip()
, mocha
會忽略這些測試套件或者測試用例。這些被跳過的測試都會被標記爲pending
。
const assert = require('assert') describe('suite 1', function () { describe('sub suite 1', function () { it('test case 1', function () { assert(true) }) it('test case 2', function () { assert(true) }) }) describe.skip('sub suite 2', function () { it('test case 3', function () { assert(true) }) }) }) describe.skip('suite 2', function () { it('test case 4', function () { assert(true) }) it.skip('test case 5', function () { assert(true) }) }) let checkTestEnviroment = false describe('suite 3', function () { it('test case 6', function () { if (checkTestEnviroment) { assert(true) } else { this.skip() } }) it('test case 7', function () { assert(true) }) })
從執行結果來看,test case 3
和 suite 2
和 test case 6
套件都進入了 pending
待定狀態。 test case 3
是由於測試用例 it.skip
。 suite 2
是由於測試套件 describe.skip
。 test case 6
是由於使用了 this.skip()
,模擬環境 checkTestEnviroment
有問題,須要跳過測試,最後跳過的測試會被標記爲 pending
。
➜ learn-mocha git:(master) ✗ mocha test/inclusive.js
suite 1 sub suite 1 ✓ test case 1 ✓ test case 2 sub suite 2 - test case 3 suite 2 - test case 4 - test case 5 suite 3 - test case 6 ✓ test case 7 3 passing (9ms) 4 pending
使用 .skip()
是比註釋更好的可以不執行指定測試的方法。
能夠選擇 this.retries(number)
來從新執行失敗的測試到必定的次數。這個函數是爲了處理資源不容易被模擬和截斷的 end-to-end
測試而設計的,因此不推薦在單元測試裏使用。
this.retries(number)
做用在 beforeEach/afterEach
hooks中,可是不做用在 before/after
hooks中。
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; }); });
mocha
使用 Function.prototype.call
和函數表達式來定義測試套件和測試用例,這樣能簡單動態的生成測試用例。不須要特別的語法,只需 javascirpt
就能實現相似參數化測試的功能。
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); }); }); });
➜ learn-mocha git:(master) ✗ mocha test/dynamically-generate.js
add()
✓ correctly adds 2 args ✓ correctly adds 3 args ✓ correctly adds 4 args 3 passing (11ms)
在許多測試報告裏會顯示測試時間,當測試時間過長,會被特殊標記出來。可使用 slow()
方法,來定義被認爲 slow
的測試時間長度。
describe('something slow', function() { this.slow(10000); it('should take long enough for me to go make a sandwich', function() { // ... }); });
在套件級別describe()
定義this.timeout(numer)
,將會被運用於該套件下的全部嵌套套件和測試用例。
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); }); })
上面的代碼定義了超時時間是500ms,而後測試執行時間都沒有超過,因此測試能夠經過
➜ learn-mocha git:(master) ✗ mocha test/timeouts/suite-level.js
a suite of tests ✓ should take less than 500ms (306ms) ✓ should take less than 500ms as well (251ms) 2 passing (564ms)
若是把時間從this.timeout(500)
改爲this.timeout(300)
,,就會的到超時錯誤
➜ learn-mocha git:(master) ✗ mocha test/timeouts/suite-level.js
a suite of tests 1) should take less than 300ms ✓ should take less than300ms as well (253ms) 1 passing (569ms) 1 failing 1) a suite of tests should take less than 300ms: Error: Timeout of 300ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/blog/learn-mocha/test/timeouts/suite-level.js)
在測試級別it()
中使用方法也差很少。在it()
中使用this.timeout(0)
能夠重載/消除測試套件定義的超時時間。
it('should take less than 500ms', function(done){ this.timeout(500); setTimeout(done, 300); });
➜ learn-mocha git:(master) ✗ mocha test/timeouts/test-level.js
✓ should take less than 500ms (302ms) 1 passing (308ms)
在鉤子級別HOOK-LEVEL
中使用方法也差很少。使用this.timeout(0)
也能夠s禁用hook
的超時。
describe('a suite of tests', function() { beforeEach(function(done) { this.timeout(3000); // A very long environment setup. setTimeout(done, 2500); }); it('it', function(done) { setTimeout(done, 20); }) });
➜ learn-mocha git:(master) ✗ mocha test/timeouts/hook-level.js
a suite of tests ✓ it 1 passing (3s)
mocha
支持來自斷言庫的有err.expected
和 err.actual
實際屬性的任何AssertionErrors
錯誤 。mocha
將自動顯示預期和實際之間的差別。下面是一個「字符串」差別的例子:
const assert = require('assert') describe('suite 1', function () { it('test case 1', function () { assert.equal(-1, [1, 2, 3].indexOf(4)) }) it('test case 2', function () { assert.equal('test', [1, 2, 3].toString()) }) })
➜ learn-mocha git:(master) ✗ mocha test/diffs.js
suite 1 ✓ test case 1 1) test case 2 1 passing (9ms) 1 failing 1) suite 1 test case 2: AssertionError [ERR_ASSERTION]: 'test' == '1,2,3' + expected - actual -test +1,2,3 at Context.<anonymous> (test/diffs.js:9:12)
➜ learn-mocha git:(master) ✗ mocha --help Usage: mocha [debug] [options] [files] Options: -V, --version output the version number -A, --async-only force all tests to take a callback (async) or return a promise -c, --colors force enabling of colors -C, --no-colors force disabling of colors -G, --growl enable growl notification support -O, --reporter-options <k=v,k2=v2,...> reporter-specific options -R, --reporter <name> specify the reporter to use (default: spec) -S, --sort sort test files -b, --bail bail after first test failure -d, --debug enable node's debugger, synonym for node --debug -g, --grep <pattern> only run tests matching <pattern> -f, --fgrep <string> only run tests containing <string> -gc, --expose-gc expose gc extension -i, --invert inverts --grep and --fgrep matches -r, --require <name> require the given module -s, --slow <ms> "slow" test threshold in milliseconds [75] -t, --timeout <ms> set test-case timeout in milliseconds [2000] -u, --ui <name> specify user-interface (bdd|tdd|qunit|exports) (default: bdd) -w, --watch watch files for changes --check-leaks check for global variable leaks --full-trace display the full stack trace --compilers <ext>:<module>,... use the given module(s) to compile files (default: ) --debug-brk enable node's debugger breaking on the first line --globals <names> allow the given comma-delimited global [names] (default: ) --es_staging enable all staged features --harmony<_classes,_generators,...> all node --harmony* flags are available --preserve-symlinks Instructs the module loader to preserve symbolic links whenresolving and caching modules --icu-data-dir include ICU data --inline-diffs display actual/expected differences inline within each string --no-diff do not show a diff on failure --inspect activate devtools in chrome --inspect-brk activate devtools in chrome and break on the first line --interfaces display available interfaces --no-deprecation silence deprecation warnings --exit force shutdown of the event loop after test run: mocha willcall process.exit --no-timeouts disables timeouts, given implicitly with --debug --no-warnings silence all node process warnings --opts <path> specify opts path (default: test/mocha.opts) --perf-basic-prof enable perf linux profiler (basic support) --napi-modules enable experimental NAPI modules --prof log statistical profiling information --log-timer-events Time events including external callbacks --recursive include sub directories --reporters display available reporters --retries <times> set numbers of time to retry a failed test case --throw-deprecation throw an exception anytime a deprecated function is used --trace trace function calls --trace-deprecation show stack traces on deprecations --trace-warnings show stack traces on node process warnings --use_strict enforce strict mode --watch-extensions <ext>,... additional extensions to monitor with --watch (default: js) --delay wait for async suite definition --allow-uncaught enable uncaught errors to propagate --forbid-only causes test marked with only to fail the suite --forbid-pending causes pending tests and test marked with skip to fail the suite --file <file> include a file to be ran during the suite (default: ) --exclude <file> a file or glob pattern to ignore (default: ) -h, --help output usage information Commands: init <path> initialize a client-side mocha setup at <path>
➜ learn-mocha git:(master) ✗ mocha --help Usage: mocha [debug] [options] [files] Options: -V, --version output the version number -A, --async-only force all tests to take a callback (async) or return a promise -c, --colors force enabling of colors -C, --no-colors force disabling of colors -G, --growl enable growl notification support -O, --reporter-options <k=v,k2=v2,...> reporter-specific options -R, --reporter <name> specify the reporter to use (default: spec) -S, --sort sort test files -b, --bail bail after first test failure -d, --debug enable node's debugger, synonym for node --debug -g, --grep <pattern> only run tests matching <pattern> -f, --fgrep <string> only run tests containing <string> -gc, --expose-gc expose gc extension -i, --invert inverts --grep and --fgrep matches -r, --require <name> require the given module -s, --slow <ms> "slow" test threshold in milliseconds [75] -t, --timeout <ms> set test-case timeout in milliseconds [2000] -u, --ui <name> specify user-interface (bdd|tdd|qunit|exports) (default: bdd) -w, --watch watch files for changes --check-leaks check for global variable leaks --full-trace display the full stack trace --compilers <ext>:<module>,... use the given module(s) to compile files (default: ) --debug-brk enable node's debugger breaking on the first line --globals <names> allow the given comma-delimited global [names] (default: ) --es_staging enable all staged features --harmony<_classes,_generators,...> all node --harmony* flags are available --preserve-symlinks Instructs the module loader to preserve symbolic links whenresolving and caching modules --icu-data-dir include ICU data --inline-diffs display actual/expected differences inline within each string --no-diff do not show a diff on failure --inspect activate devtools in chrome --inspect-brk activate devtools in chrome and break on the first line --interfaces display available interfaces --no-deprecation silence deprecation warnings --exit force shutdown of the event loop after test run: mocha willcall process.exit --no-timeouts disables timeouts, given implicitly with --debug --no-warnings silence all node process warnings --opts <path> specify opts path (default: test/mocha.opts) --perf-basic-prof enable perf linux profiler (basic support) --napi-modules enable experimental NAPI modules --prof log statistical profiling information --log-timer-events Time events including external callbacks --recursive include sub directories --reporters display available reporters --retries <times> set numbers of time to retry a failed test case --throw-deprecation throw an exception anytime a deprecated function is used --trace trace function calls --trace-deprecation show stack traces on deprecations --trace-warnings show stack traces on node process warnings --use_strict enforce strict mode --watch-extensions <ext>,... additional extensions to monitor with --watch (default: js) --delay wait for async suite definition --allow-uncaught enable uncaught errors to propagate --forbid-only causes test marked with only to fail the suite --forbid-pending causes pending tests and test marked with skip to fail the suite --file <file> include a file to be ran during the suite (default: ) --exclude <file> a file or glob pattern to ignore (default: ) -h, --help output usage information Commands: init <path> initialize a client-side mocha setup at <path>
解釋幾個經常使用的選項
-V, --version
版本號-b, --bail
只對第一個拋出異常處理-d, --debug
開啓node的debug模式,對標記了debugger語句的代碼進行調試-t, --timeout <ms>
指定測試用例的超時時間。默認是2000毫秒。-w, --watch
用來監測測試文件的變化-s, --slow <ms>
指定測試用例執行時間爲慢的閾值。默認是75毫秒。mocha
的接口系統容許開發人員選擇本身的DSL風格。mocha
擁有 BDD
, TDD
, Exports
, QUnit
和 Require
風格的接口。
BDD
接口 提供 describe()
, context()
, it()
, specify()
, before()
, after()
, beforeEach()
, afterEach()
。 describe()
= context()
, it()
= specify()
前面的例子都是用的 BDD 接口。
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); }); }); }); });
提供 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)); }); }); });
相似於 mocha
前身 expresso
。關鍵字 before
, after
, beforeEach
, afterEach
是special-cased
。 測試套件是對象,函數是測試用例。
module.exports = { before: function() { // ... }, 'Array': { '#indexOf()': { 'should return -1 when not present': function() { [1,2,3].indexOf(4).should.equal(-1); } } } };
相似QUnit
。測試套件單獨定義在測試用例以前,像TDD同樣支持suite()和test(),像BDD同樣支持hooks。一樣包括before()
, after()
, beforeEach()
, afterEach()
。
unction 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()
來導入describe()
和it()
的方法。能夠本身定義別名。注意:只能用mocha
命令執行,node
不行。
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
提供了多種console端報告模式
mocha --reporter spec
這是默認模式。是一個按照測試套件和用例分層次的視圖mocha --reporter dot
顯示一個由點組成的矩陣。點的顏色表明着不一樣的測試結果mocha --reporter nyan
顯示了一個圖。。。。。mocha --reporter tap
基於Test Anything Protocol (TAP)mocha --reporter landing
模擬飛機降落mocha --reporter list
以列表的形式顯示每個測試用例mocha --reporter progress
以進度條的形式顯示mocha --reporter json
輸出json格式的報告mocha --reporter min
只輸出summary。能夠與mocha -w一塊兒使用mocha --reporter doc
輸出HTML格式的報告mocha --reporter markdown
輸出HTML格式的報告參照連接: