簡單的 JavaScript 自動單元測試

前幾天弄完 JSLint.vim 後,就對 server side JavaScript 產生了一些興趣,還抓了 v8 引擎 來用,於是就想到之前想弄很久的自動單元測試,想說要跑 QUnit ,不過 QUnit 雖然獨立於 jQuery 了,但還是要在瀏覽器環境下才能執行,純 JavaScript engine 還少了 DOM 和 BOM,就是說它需要 document, window 這些物件,找了一下發現 John Resig 有弄 env.js 這個專案,就是要在 js shell 裡面做出瀏覽器的環境,不過問題是目前只能跑在 Rhino 下,因為他是 java based ,可以在 JavaScript 裡面寫 Java ,所以可以做很多壞事,但是其他的 js shell 沒辦法這樣跑, John Resig 好像有想要 port 成 python + v8 的版本,不過不知道有沒有成功,因為也 沒放出 。

剛好最近有點紅的 node.js ,似乎可以拿來做一樣的事情(要做 http request、開檔案、DOM),於是也調查了一下,結果缺少了重要的 DOM ,這樣也跑不起 Qunit,傷心難過之餘只好把方向改成尋找簡單的 JavaScript Unit Test Framework,希望能找到不會存取到 BOM 和 DOM 的版本,結果找到 這個 ,雖然沒完全符合需求,不過裡面要改的地方很少,所以改了一下就拿來用了(還不知道授權所以不敢丟出來),把幾個要用到 jQuery, DOM 的地方註解掉,還有 log 改成有錯誤才輸出,然後 ~/.vimrc 加上:

function Jsunit ()
    let ut = 'unit.test.js'
    let fn = expand('<afile>:t')
    if fn != ut
        let cwd = expand('<afile>:p:h')
        if filereadable(cwd.'/unit.test.js')
            let has_error = 0
            let cmd = 'js '. ut
            let output = system(cmd)
            for error in split(output, "\n")
                let has_error = 1
                caddexpr expand("%") . fn . ":0:0:" . error
            endfor
            if has_error == 1
                copen
            else
                echo 'Unit  : All OK.'
            endif
        endif
    endif
endfunction

autocmd FileWritePost,BufWritePost *.js :call Jsunit()

存檔的時候會自動找 unit.test.js ,如果存在的話就會執行它,unit.test.js 裡面長得像這樣:

load('testrunner.js');
load('lib.js');

test('all', function () {
    ok(libFunc(true) == 530, 'send true');
    isObj(libFunc(false), {a:'1'}, 'send false');
});

不過這個 testrunner 不能做任何和 html 文件、瀏覽器有關的測試,只能做很核心部份的測試。