本文是最近在学习 Node.js 测试方面的总结,包括单元测试、集成测试、基准测试以及代码覆盖率测试等多方面的的内容。对于中大型项目,完备的测试用例有助于保证项目的持续集成能力和代码的健壮性。
Unit Test 单元测试,又称模块测试,针对程序中的最小执行单元进行正确性测试。常见的开发模式包括 TDD 和 BDD 两类。
TDD(Test-driven development,测试驱动开发),先编写测试用例,然后针对测试用例开发模块,当测试用例不足时,补充测试用例;当模块无法通过测试时,持续更新模块代码,直到完全通过测试用例。其开发核心围绕测试用例展开,即测试用例的完整性决定了开发模块的健壮性和正确性,这容易由边界条件引发单元测试覆盖度不够的问题。
BDD(Behavior-driven development,行为驱动开发),用语义化的编程语言开发紧贴业务需求的测试用例,继而驱动相关模块的开发。
AVA 是 JavaScript 生态中最新潮的测试框架,其内置了 Babel,可以直接使用 ES6 语法,具有轻量高效、并发执行、强制隔离等优点,安装方法:
npm install --save-dev ava
|
設定 package.json 中的 scripts 欄位:
{{
"scripts": {
"test": "ava",
"test:watch": "ava --watch"
}
}
|
"scripts": {
"test": "ava",
"test:watch": "ava --watch"
}
}
|
npm test
# or
npm test:watch
|
運行:
npm test
# 或import test from 'ava';
const fibonacci = (n) => {
if (n === 0 || n === 1) {
return n;
}
return fibonacci(n - 1) fibonacci(n - 2);
}
test('Test Fibonacci(0)', t => {
t.is(fibonacci(0), 0);
});
test('Test Fibonacci(1)', t => {
t.is(fibonacci(1), 1);
});
// HOOK CALLS
test.before('Before', t => {
console.log('before');
});
test.after('After', t => {
console.log('after');
});
test.beforeEach('BeforeEach', t => {
console.log(' beforeEach');
});
test.afterEach('AfterEach', t => {
console.log(' afterEach');
});
|
npm test:watch
|
以下是一個基本的測試程式碼:
import test from 'ava';
const fibonacci = (n) => {
if (n === 0 || n === 1) {
return n;
}
return fibonacci(n - 1) fibonacci(n - 2);
}
test('Test Fibonacci(0)', t => {
t.is(fibonacci(0), 0);
});
test('Test Fibonacci(1)', t => {
t.is(fibonacci(1), 1);
});
// HOOK CALLS
test.before('Before', t => {
console.log('before');
});
test.after('After', t => {
console.log('after');
});
test.beforeEach('BeforeEach', t => {
console.log(' beforeEach');
});
test.afterEach('AfterEach', t => {
console.log(' afterEach');
});
|
在上面的程式碼中,我們首先引入了AVA 模組,然後創建了待測試的fibonacci 函數,接下來是兩個測試案例,最後是四個鉤子方法:before() / after() / beforeEach() / afterEach()。
AVA 提供了修飾方法來指定測試的執行方式:
1、skip(),跳過新增了skip() 的測試案例;
2、only(),只執行新增了only() 的測試使用案例;
3、todo(),佔位標識符,表示將來需要新增的測試案例;
4、serial() ,串行執行測試案例,預設情況下AVA 會以並行的方式執行測試案例。
test('Test Fibonacci(0)', t => {test('Test Fibonacci(0)', t => {
t.is(fibonacci(0), 0);
});
|
t.is(fibonacci(0), 0);
});
|
在上面程式碼回呼函數中的 t,稱為斷言執行對象,該物件包含以下方法:
· t.end(),結束測試,只在test.cb() 中有效
· t.plan(count),指定執行次數
· t.pass([message]),檢定通過
· t.fail([message]),測試失敗
· t.ok(value, [message]),斷言value 的值為真值
· t.notOK(value, [message]),斷言value 的值為假值
· t.true(value, [message]),斷言value 的值為true
· t .false(value, [message]),斷言value 的值為false
· t.is(value, expected, [message]),斷言value === expected
· t.not(value, expected, [message]),斷言value !== expected ·t.same(value, expected, [message]),斷言value 和expected 深度相等
···t
·t .notSame(value, expected, [message]),斷言value 和expected 深度不等
·t.throws(function | promise, [🎜>·t.throws(function | promise, [lerror, [ message]]),斷言function 拋出異常或promisereject 錯誤
·t.notThrows(function | promise, [message]),斷言function 不會異常斷言或promise resolve
·t.regex(contents, regex, [message]),斷言contents 匹配regex
· t.ifError(error, [message]),斷言error 是假值
language: node_js
node_js:
- "6"
- "5"
before_script:
script:
- npm test
- node benchmark/index.js
after_script:
|
整合測試
相對於專注微觀模組的單元測試,整合測試是從宏觀整體的角度發現問題,所以也稱為組裝測試和聯合測試。 Travis CI 是一款優秀的持續整合工具,可監聽 Github 專案的更新,以便於開源軟體的整合測試。使用 Travis CI 需要在專案的根目錄下建立 .travis.yml 設定檔(以 Node.js 為例):
language: node_js
node_js:
- "6"
- "5"
before_script:
script:
- npm test
- node benchmark/index.js
after_script:
|
預設情況下,Travis CI 會自動安裝依賴並執行 npm test 指令,透過 script 欄位可以自訂需要執行的指令,其完整的生命週期包括:
·Install apt addons
·before_install ·before_install·install
·before_script
·
·after_success or after_failure
·OPTIONAL deploy
·OPTIONAL after_deploy
· after_script
基準測試
基準測試使用嚴謹的測試方法、測試工具或測試系統評估目標模組的效能,常用於觀測軟硬體環境變化後的效能表現,其結果具有可重現性。在 Node.js 環境中最常使用的基準測試工具是 Benchmark.js,安裝方式:
npm install --save-dev benchmark
|
基本範例:
const Benchmark = require('benchmark');npm install --save-dev benchmark
|
const suite = new Benchmark.Suite;
suite.add('RegExp#test', function() {
/o/.test('Hello World!');
})
.add('String#indexOf', function() {
'Hello World!'.indexOf('o') > -1;const Benchmark = require('benchmark');
const suite = new Benchmark.Suite;
suite.add('RegExp#test', function() {
/o/.test('Hello World!');
})
.add('String#indexOf', function() {
'Hello World!'.indexOf('o') > -1;
})
.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Fastest is ' this.filter('fastest').map('name'));
})
// run async
.run({ 'async': true });
|
})
.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Fastest is ' this.filter('fastest').map('name'));
})
// run async
.run({ 'async': true });
|
npm install nyc --save-dev
|
程式碼覆蓋率
程式碼覆蓋率工具根據測試案例所涵蓋的程式碼行數和分支數來判斷模組的完整性。 AVA 建議使用 nyc 測試程式碼覆蓋率,安裝 nyc:node_modules
coverage
.nyc_output
|
npm install nyc --save-dev
|
修改 .gitignore 忽略相關文件:{
"scripts": {
"test": "nyc ava"
}
}
|
node_modules
coverage
.nyc_output
|
➜ test-in-action (master) ✔ npm test
> test-in-action@1.0.0 test /Users/sean/Desktop/test-in-action
> nyc ava
2 passed
----------|----------|----------|----------|----------|----------------|
File | % Stmts | % Branch | % Funcs | % Lines |Uncovered Lines |
----------|----------|----------|----------|----------|----------------|
----------|----------|----------|----------|----------|----------------|
All files | 100 | 100 | 100 | 100 | |
----------|----------|----------|----------|----------|----------------|
|
修改 package.json 中的 test 欄位:
{
"scripts": {
"test": "nyc ava"
}
}
|
執行 npm test,得到:
➜ test-in-action (master) ✔ npm test
> test-in-action@1.0.0 test /Users/sean/Desktop/test-in-action
> nyc ava
2 passed
----------|----------|----------|----------|------ ----|----------------|
File | % Stmts | % Branch | % Funcs | % Lines |Uncovered Lines |
----------|----------|----------|----------|------ ----|----------------|
----------|----------|----------|----------|------ ----|----------------|
All files | 100 | 100 | 100 | 100 |
----------|----------|----------|----------|------ ----|----------------|
|
由於上傳附件及文字限制,有時部分圖片、文字可能顯示不了,詳情請見: http://mp.weixin.qq.com/s?__biz=MzI5ODI3NzY2MA==&mid=100000510&idx=2&sn=8339d4fca5f54ab3a9ec305eae756436#rd
歡迎大家一起交流。 掃描以下二維碼,取得更多更精美文章! (掃碼關注有意向不到的驚喜的哦!!)
訂閱號碼二維碼.jpg
追蹤我們微信訂閱號碼( uniguytech100) 與服務號碼(uniguytech),取得更多更精美文章! 也歡迎加入【大家技術網討論QQ群】,群號碼:256175955,請備註你個人的介紹!讓我們一起聊聊it的那些事吧!
|