像我這樣優秀的猿,本該程式碼敲一生,怎麼我的 Github 上,還是沒有一個好專案?。
像我這樣的人,遇見不爽,一言不合就要造輪子,開了好多的坑,很多臨時的專案,為了 A 而誕生 B,所以也就只能保正在相關專案中可用,如果有另一個專案要呼叫時,都是提心吊膽的,生怕越寫越不好收場。
最近決定,把自己的程式碼都好好整理一下,能釋出的也別讓它就安息了,怎麼說它也是我思想邏輯的延續,親生的啊。
這篇也算是我 blog 的第一篇文章了,為什麼寫了這個題目,因為這是我遇到的第一個問題,參觀了一些知名專案的單元測試,看的我淚流滿面的,這工作量可是感人啊,還有簡單看了現在比較流行的單元測試庫,API 也太豐富了吧,並且也太不好用了吧,所以我這脾氣怎麼能忍,當時就決定造新輪子。
我理解的單元測試功能,小專案友好的,能讓你知道修改了程式碼後,是否還能正常執行就可以了,僅此而已,沒有更多,那就開始介紹我的新坑吧,hi-test 單元測試庫。
安裝
$ npm install hi-test
複製程式碼
專案 github 地址:github.com/wl879/hi-te…
API 我就不在這理堆列了,也沒什麼功能,直接介紹使用。
使用
0. 檢視專案的API
$ hi-test scan <path>
複製程式碼
這條命令會掃描目錄中所有 js 檔案的 exports, 並列出來,算是一個輔助功能
1. 開始寫測試程式碼
先來建立一個模組,功能為拆分字串,但需要跳過轉義字元
exports.explode = function (str, separator) {
let re = new RegExp('(\\\\+)?\\' + separator);
let offset = 0;
let ref = [];
let m;
while (m = str.substr(offset).match(re) ) {
let esc = m[1] ? m[1].length : 0;
if (!esc || esc % 2 === 0) {
ref.push(str.substr(0, offset + m.index + esc));
str = str.substr(offset + m.index + m[0].length);
offset = 0;
} else {
offset += m.index + m[0].length;
}
}
ref.push(str);
return ref;
};
複製程式碼
接下來寫測試程式碼,如下
const test = require('hi-test');
const explode = require('./index.js').explode;
test('測試 "無"轉義符', (t)=>{
t.log(explode('hello, world', ','));
});
test('測試 "有"轉義符', (t) => {
t.log(explode('hello\\, world', ','));
});
test('測試 "多"轉義符', (t) => {
t.log(explode('hello\\\\\, world', ','));
t.log(explode('hello\\\\\\, world', ','));
});
複製程式碼
執行後輸出如下,檢查一下,輸出是否是對的!嗯,是對的!!
這裡的工作邏輯,是使用 t.log()
輸出你想要測試的結果,t.log
不同於 console.log
輸出會更詳細,還有另一個函式 t.logp()
會更詳細一點,包括變數的型別。
提示:如果變數中包含隨機數或時間戳,或類名稱的改變,會對測試有點麻煩,原因請往下看。
2. 如果輸出是對的,還須要把 hash 碼還給我
到這裡,測試所寫的程式碼以完成 99% 了,是不是沒有那些 equal
/deepEqual
的API,感覺不像測試的正確用法,是不是上當了,這不就是普通除錯時寫的程式碼嗎,對與錯,基本靠瞅。
是的,很可惜,還不夠智慧,第一次的輸出只能靠瞅來判斷對錯,好在你只需要瞅一次,如果輸出結果是對的,你還須要這樣做。
呼叫 hi-test
的 enable
方法.
var test = require('hi-test').enable();
複製程式碼
這時的輸出就會是這樣了,格式有點熟悉了
呼叫 enable
方法,開啟 hi-test 後,會有以下改變:
- 遮蔽掉無用的輸出
- 自動新增 hash 碼
What?? 什麼是 hash 碼,什麼鬼。
檢視一下,在上面的示例的輸出中,在 [Test Done]...
那一行,Title 後面會跟著一串(黃色的) hash 碼,這是由捕獲到的輸出生成的 md5 值,hi-test 也就是通過它來判斷測試是否正確的。
如果程式正確,它的每次的輸出應該是一致的,所以反過來,通過判斷兩次輸出是否一致,也就可以判斷程式是否正確。當然這不能適用所有場景,但對於簡單的測試還是基本靠譜的(相較於感人的測試程式碼量)。
手動新增 hash 碼
只需要將 hash 碼做為第二個引數加到 test 函式中即可
test('測試 "無"轉義符', 'ff34b7', (t)=>{
....
})
複製程式碼
以上就是一個測試的全部流程了,是不是夠簡化的了。
3. 其它你還需要了解一下的
這裡還要特殊的說明一點,test 間是阻塞執行的,只有上一個 done 之後,後面的才會執行,而 t.done()
是可以自動呼叫的,是通過監聽 process.on('beforeExit') 來實現,所以一般情況下可以不用手動呼叫,這樣它會在對的時間點被呼叫。
還有一種情況,如果呼叫的 func 是 aync function , 這將會在 func 結束時隱式呼叫 t.done()
, 這種情況適用於以下例子:
var test = require('hi-test')
let timing = setInterval(()=>{
console.log('Hi, See you again!');
}, 1000);
test('start', 'e893ed', async (t) => {
t.log('Hello, Start');
});
test('end', 'd41d8c', (t) => {
clearInterval(timing);
t.log('Hello, End');
)};
複製程式碼
例子中,如果不手動呼叫 t.done
,或用 async function 隱式呼叫,程式會一直的輸出 See you again
。
如果你就是需要並行執行測試,可以這樣寫:
const test = require('hi-test');
const explode = require('./index.js').explode;
test('測試 "無"轉義符').run((t)=>{
t.log(explode('hello, world', ','));
});
test('測試 "有"轉義符').run((t) => {
t.log(explode('hello\\, world', ','));
});
複製程式碼
篩選輸出
每一個 test 的輸出中,都會有一個標識,看這裡
其中 7e55
就是標識,它是由 md5(title) 得來的,所以當你只想檢視某一項測試輸出時,你可以用它來篩選,像這樣
$ node ./test.js | grep '7e55'
複製程式碼
$ hi-test ./tset.js -df '測試 "無"轉義符'
複製程式碼
測試垃圾回收
這裡有一個實用的小功能,可以測試某一個變數是否被回收
var test = require('hi-test').enableGC();
var num = [1, 2, 3];
test('CG', (t)=>{
t.gc(num, 'num');
// num = null;
});
test('Next', (t) => {
console.log(num);
});
複製程式碼
如果變數 num
被回收則輸出
[Test GC ] [Yes] >> num
複製程式碼
未被回收的話
[Test GC ] [No] >> num
複製程式碼
4. 開始測試吧
最後介紹一下 hi-test 的命令列,直接看幫助
Usage:
hi-test <files> [-d] [-a] [-f <title>]
Options:
+scan <path> Scan module exports
-f, --filter <title> Filter the output
-d, --debug Display all output
-a, --auto Automation
-v, --version Display version
-h, --help Display help
複製程式碼
在 package.json 中新增上這些一段
"scripts": {
"test": "hi-test tests/test-*.js -a",
}
複製程式碼
收工!!