自動化測試軟體對于開發來說是一個很重要的工具,而單元測試對于自動化測試來說是基本組成部分:軟體的每一個元件或者單元可以在非人工介入的情況下,使用測試工具一遍遍的重複執行。換句話說,就是你可以寫一次測試,然後不用付出額外成本的任意執行多次。
除了測試覆寫率帶來的好處外,測試還可以指導軟體設計,這就是TDD(基于測試驅動的設計):先有測試,後有開發代碼。你開始寫一個簡單的測試,然後寫實作代碼并保證代碼能通過測試。完成上述步驟後,擴充你的測試,讓他覆寫更多設計功能,然後再編寫實作代碼。重複上面的步驟直到完成開發,你會發現你的實作代碼和之前的版本已經非常不一樣了。
JavaScript的單元測試和其他語言沒什麼不同,你需要一個提供測試運作器的小架構,他同時提供寫測試用例的工具。
你想自動化測試你的應用和架構,甚至想使用TDD的開發方式。你或許會想些一個自己的測試架構,但是那需要很多額外的工作,涉及到太多的細節,還需要處理在不同浏覽器中測試JavaScript的問題。
現在已經有很多JavaScript的單元測試架構了,例如你可以選擇QUnit。QUnit是jquery使用的單元測試架構,而且他已經被廣泛的使用在了不同的項目中。使用QUnit很簡單,你隻需要添加兩個相關檔案到你的html頁面即可。QUnit包括qunit.js:測試運作器和測試架構,qunit.css:測試頁面用于顯示測試結果的css檔案。
在浏覽器中打開上面的檔案,顯示結果如下:
唯一需要的标簽是<body>中含有id="qunit-fixture"的<div>,他對于所有QUnit的測試都是必須的,即使這個div元素是空的,他為測試提供夾具(fixture),我們會在“保持測試原子性”中詳細介紹。
有趣的部分是跟在測試運作器(qunit.js)後面的腳本标簽,他包含一個test方法。他包含兩個參數,第一個參數是字元串類型,表示測試名稱,他将會顯示在測試結果和方法上。第二個參數是一個函數,包含實際的測試代碼。他包含一個或者多個斷言,上面的例子包含兩個斷言:ok() 和 equal()。我們會在“斷言結果”中詳細介紹。
我們注意到這裡沒有使用到document-ready,這次因為測試運作器會把test()添加到測試隊列中,測試用例會被延遲執行。
測試套件的頁眉顯示頁面名稱,所有測試通過的時候,顯示綠條;當至少有一條測試失敗的時候顯示紅條。有選擇框可供過濾結果,此外還有一個藍條用來顯示浏覽器資訊。選擇框中有"Hide passed tests",當測試很多的時候可以使用它隐藏成功的測試,隻顯示失敗的測試。
選擇“noglobals”,會讓QUnit在每次測試的開始和結束的時候羅列window的所有屬性,并比較不同點。如果存在屬性的添加和删除操作,測試失敗,并顯示不同點資訊。這樣可以驗證我們的測試代碼和被測試代碼沒有暴露任何的全局屬性。
“notrycatch”選擇框的作用是,告訴QUnit不使用try-catch跑測試,當有異常抛出的時候,測試運作器會停止運作。但是你會獲得一個内部異常,這樣在我們使用老浏覽器(例如ie6)做測試的時候會有幫助。
頁眉之下是測試總結,顯示測試總用時,成功和失敗的測試總數。當測試還在運作的時候,他會顯示哪個測試用例正在被執行。
頁面的主體部分是測試結果,每個實體以名字開頭,後面跟着失敗數、成功數和總斷言數。點選實體将會顯示每一個斷言,經常會顯示期望值和實際值。最後的“Rerun”連結會單獨運作測試實體。
任何單元測試的實際元素都是斷言,測試的開發者需要使用測試架構,将期望值和運作測試獲得的實際值進行比較。
QUnit提供三種斷言。
ok()是最基本的方法,他隻需要一個參數,如果參數等于true,斷言成功,否則失敗。例外他還接受額外的字元串參數,用于顯示測試結果。
equal()方法使用簡單的比較符(==)來比較期望值和實際值。當他們相等的時候,斷言成功,否則失敗。當失敗的時候,期望值和實際值都會顯示,另外還顯示消息。
使用ok() 和 equal()讓我們更容易的找到失敗的測試,因為測試失敗的時候他會很明顯的告訴我們哪個值導緻了問題。當你需要使用嚴格比較(===)的時候,可以使用strictEqual()。
deepEqual()可以像equal()那樣使用,但是他适用的場景更多。他不是使用簡單比較符(==),他使用的是更精确的比較符(===)。這種情況下,undefined不等于null,0或者空字元串(“”)。他同時也比較對象的内容,<code>{key: value} 等于</code> <code>{key: value},甚至比較的兩個對象有不同的執行個體。deepEqual()同樣也處理NaN,dates,正規表達式,數組和函數,而equal()隻檢查對象執行個體。</code>
如果你不想明确的比較兩個對象的内容仍然可以使用equal(),但是deepEqual()是更好的選擇。
有時候你的代碼可能會阻止回調斷言的執行,導緻測試無聲無息的就失敗了。
QUnit提供了一個特殊的斷言,定義了測試包含的總斷言數。當測試結束的時候,斷言總數不相等,無論其他斷言的執行情況,都會傳回失敗。使用上也相當簡單,在測試開始的時候調用expect(),隻需要傳遞期望的斷言數作為方法參數。
另外一種方式是,把期望斷言數作為他的第二個參數傳給test():
執行個體:
雖然expect()對于同步回調的測試是有幫助的,但他不能用來處理異步回調的測試,異步回調和測試運作器中的執行隊列的執行相沖突。在測試代碼中執行一個timeout、interval或者ajax請求的時候,測試運作器隻是會繼續執行測試用例剩餘的代碼,然後接着執行測試隊列中剩餘的用例,而不會去執行異步操作。
我們不使用test(),取而代之将使用asyncTest(),當你的測試代碼執行完畢準備繼續的時候執行start()。
執行個體:
<a href="http://www.vancl.com/?source=kbh1983&sourcesuninfo=ad-3090-1-52-0-1" target="_blank"></a>