有心無力,適合小專案的 Nodejs 單元測試

wl879發表於2017-11-30

有心無力,適合小專案的 Nodejs 單元測試

像我這樣優秀的猿,本該程式碼敲一生,怎麼我的 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', ','));
});
複製程式碼

執行後輸出如下,檢查一下,輸出是否是對的!嗯,是對的!!

有心無力,適合小專案的 Nodejs 單元測試

這裡的工作邏輯,是使用 t.log() 輸出你想要測試的結果,t.log 不同於 console.log 輸出會更詳細,還有另一個函式 t.logp() 會更詳細一點,包括變數的型別。

提示:如果變數中包含隨機數或時間戳,或類名稱的改變,會對測試有點麻煩,原因請往下看。

2. 如果輸出是對的,還須要把 hash 碼還給我

到這裡,測試所寫的程式碼以完成 99% 了,是不是沒有那些 equal/deepEqual 的API,感覺不像測試的正確用法,是不是上當了,這不就是普通除錯時寫的程式碼嗎,對與錯,基本靠瞅。

是的,很可惜,還不夠智慧,第一次的輸出只能靠瞅來判斷對錯,好在你只需要瞅一次,如果輸出結果是對的,你還須要這樣做。

呼叫 hi-testenable 方法.

var test = require('hi-test').enable();
複製程式碼

這時的輸出就會是這樣了,格式有點熟悉了

有心無力,適合小專案的 Nodejs 單元測試

呼叫 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 的輸出中,都會有一個標識,看這裡

有心無力,適合小專案的 Nodejs 單元測試

其中 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",
}
複製程式碼

收工!!

相關文章