單元測試
基本概念
- 英文 Unit Testing,又稱為模塊測試。
- 單元測試本質上也是代碼,與普通代碼的區別在于它是驗證代碼正確性的代碼。
- 單元測試是由開發人員編寫的、用于檢測在特定條件下目標代碼正確性的代碼。
- 單元測試是針對程序模塊(軟件設計的最小單位。面向過程編程(OPP)中,一個單元就是單個程序、函數、過程等;面向對象編程(OOP)中,最小單元就是方法,包括基類(超類)、抽象類、或者派生類(子類)中的方法。)來進行正確性檢驗的測試工作。
- 單元測試允許程序員在未來重構代碼,并且確保模塊依然工作正確(復合測試)。在代碼變更導致錯誤時,程序員可以借助單元測試快速定位并修復錯誤,因此單元測試的編寫需要良好的設計性與可讀性。
- 單元測試可以自動進行也可以手動執行,雖然 IEEE 并沒有明確表示偏愛哪一種方式,但是自動進行的單元測試能更好地節省開發人員的時間與精力。
- 極限編程(Extreme Programming,XP)提倡在功能開發前先進行單元測試,以激勵程序員設想出代碼會在何種條件下出錯的種種可能情況。極限編程認為當程序員無法再想出更多能使代碼出錯的情況時,代碼才算真正意義上的完成。
作用
- 便于后期重構。單元測試可以為代碼的重構提供保障,只要重構代碼之后單元測試全部運行通過,那么在很大程度上表示這次重構沒有引入新的 BUG,當然這是建立在完整、有效的單元測試覆蓋率的基礎上。
- 提供優化設計的思路。編寫單元測試將使用戶從調用者的角度觀察、思考,特別是使用 TDD 驅動開發的開發方式,會讓使用者把程序設計成易于調用和可測試,并且解除軟件中的耦合。
- 具有文檔記錄的功效。單元測試就是一種無價的文檔,它是展示函數或類如何使用的最佳文檔,這份文檔是可編譯、可運行的、并且它保持最新,永遠與代碼同步。
- 具有回歸性。編寫完成之后,可以隨時隨地地快速運行測試,而不是將代碼部署到設備之后,然后再手動地覆蓋各種執行路徑,這樣的行為效率低下,浪費時間。
影響
- 給開發人員帶來自信。在接手一個新的項目,或者說是參與一個新的項目開發時,往往這種情況是你半途參加進去的,你需要對已有的代碼結構進行解讀和理解,對于業務的理解,對于代碼個中各個模塊關系的理解。如果一開始就理解出錯,就算是簡單的修改也很可能引起更多的 BUG 出現,到那時候又需要修復更多的 BUG,改了一個地方,很有可能會莫名其妙地影響另外一個地方,這種現象是很常見的。還有一種情況,假設你修改的功能沒問題,但是需要去測試驗證,在測試時就需要考慮這個功能點它原有的測試路徑有哪些,又需要一一去驗證功能路徑,以證明本次修改對于已存在的功能點不造成影響。這其中就存在著很大的時間成本,導致效率不高。那是否存在這么一種方式,開發人員需要修改其想改動的地方,不需要關心修改完之后它所造成的影響,也不需要關心它的測試回歸性,答案是有的,此時就是單元測試登場的時候。寫單元測試代碼,可以讓開發人員寫的代碼足夠自信,因為它是經得起考驗的。
- 能提供更快的反饋。對于有一定編程經驗的開發人員來說,當其遇到一個新需求時,首先想到的不是動手 Coding ,而是會先想想代碼的結構,有些類,數據結構當是如何,然后才開始敲代碼。如果沒有單元測試,一般流程基本是這個模塊功能全部寫完才開始測試,比如典型的 MVC 架構,通常是 Model ——> Controller ——> View 這樣一個流程,只有這個流程全部結束了才開始驗證寫的功能模塊是否符合需求,如果沒有符合則需要返回去修改代碼,這中間需要花費很長的時間才能知道當下自己寫的代碼是否符合要求,是否正確。那有沒有一種即時反饋的方式呢,答案依然是有的,寫單元測試即可,當你寫完一個函數,馬上就匹配一個單元測試函數,這樣即寫即測的方式可以保證你當場寫的代碼可以馬上進行修改,測試通過一個,就表示完成一個小的功能點,直到最后把函數組裝起來,我們要的功能點也就完成了。如果擔心新添加的功能點對其他功能點有影響,我們只需要跑一遍完整的單元測試就好了,如果出現的錯誤是新功能點引起的,修改好讓其再次順利通過即可,如果原來的單元測試本身就存在問題,這樣就需要找到相關的負責人來一起解決,避免出現片面的功能點理解,這便是極限編程中的結對編程希望看到的結果。
- 能為開發人員節約大量的時間。當然在項目伊始可能不是節省時間而是耗費時間,因為進行單元測試可能需要依賴于第三方框架,我們需要進行環境的搭建與熟悉代碼的編寫等額外的工作,這也是單元測試為什么沒有得到很好的推廣的一個重要原因,這部分的時間與金錢的投入使很多的項目負責人望而卻步甚至直接將單元測試放棄了,因此這里所說的能為開發人員節省大量的時間是從長遠來說的。對于一個存在已久的大型項目來說,不管是添加新功能還是進行重構,不可避免地需要驗證新功能或者重構是否會對原有功能造成一些破壞性的影響,如果沒有單元測試的保障,就需要重復性地一遍遍執行整個流程來進行驗證,這里面將要花費的時間可想而知。如果絕大部分的功能在單元測試階段就能驗證完畢,那么速度就相對快很多。此外,單元測試還能幫忙減少 BUG ,從而減少調試 BUG 的時間,一些低級犯的錯誤在單元測試階段就能避免掉。
第三方框架
Jest
Jest 是 Facebook 的一套開源的 JavaScript 測試框架, 它自動集成了斷言、JSDom、覆蓋率報告等開發者所需要的所有測試工具,是一款幾乎零配置的測試框架。其具有以下特點:
- 零配置——Jest 的目標是在大部分 JavaScript 項目上實現開箱即用,無需配置。
- 快照——構建能夠輕松追蹤大 Object 的測試。快照可以獨立于測試代碼,也可以集成進代碼行內。
- 隔離的——測試程序在自己的進程并行運算以最大限度地提高性能。
- 優秀的 api——從 it 到 expect - Jest 將整個工具包放在一個地方。好書寫,好維護,非常方便。
- 快速且安全——通過確保你的測試具有獨一無二的全局狀態,Jest 可以可靠地并行運行測試。 為了讓加速測試進程,Jest 會先運行先前失敗的測試,并根據測試文件需要多長時間重新組織測試。
- 代碼覆蓋率——通過添加--coverage 標志生成代碼覆蓋率報告,無需額外設置。Jest 可以從整個項目收集代碼覆蓋面信息,包括未經測試的文件。
- 輕松模擬——Jest 支持針對你的測試文件引用使用使用自定義解析器,使得模擬任何超出您測試范圍的對象變得簡單。 您可以用功能齊全的Mock 功能API 來使用模擬導入函數和可讀測試語法進行調用.
- 優秀的報錯信息——測試失敗——當測試報錯時,Jest 會提供豐富的上下文內容。
Mocha
Mocha 是一個功能豐富的 javascript 測試框架,運行在 node.js 和瀏覽器中,使異步測試變得簡單有趣。Mocha 測試連續運行,允許靈活和準確的報告,同時將未捕獲的異常映射到正確的測試用例。使用 Mocha,我們就只需要專注于編寫單元測試本身,然后讓 Mocha 去自動運行所有的測試,并給出測試結果。
- 功能豐富。
- 使用靈活。
- 支持異步。
- 需要額外的斷言支持。
- 不僅允許運行所有的測試,也允許執行特定的測試。
- 支持鉤函數,可以支持 before、after、beforeEach 和 afterEach 來編寫初始化代碼。
Jasmine
Jasmine 是一個行為驅動的開發框架,用于測試 JavaScript 代碼。它不依賴于任何其他 JavaScript 框架。它不需要 DOM。而且它的語法簡潔明了,因此您可以輕松編寫測試。
- 開銷低,無需額外的依賴。
- 開箱即用,提供測試代碼所需的一切。
- 支持瀏覽器測試與 Node.js 測試。
AVA
AVA 可以幫助您完成復雜麻煩的測試。AVA 是 Node.js 的測試運行程序,具有簡潔的 API,詳細的錯誤輸出,新的語言功能和流程隔離功能,可讓您更有效地編寫測試。因此,您可以通過 AVA 發布更出色的代碼。
- 異步,性能好。
- 輕量,高效,簡單。
- 快照測試和斷言需要三方支持。
- 并發測試,強制編寫原子測試。
- 沒有隱藏的全局變量,每個測試文件獨立環境。
- 內置斷言,強化斷言信息。
- 可選的 TAP 輸出顯示。
Tape
- 體積最小,只提供最關鍵的東西。
- 對比其他框架,只提供最底層的 API。
- 支持瀏覽器測試與 Node.js 測試。
如果你希望得到很好的社區支持與靈活的個性化配置測試,Mocha 將是最好的選擇;如果你希望不僅開箱即用又能提供全面的測試方案,Jest 將是不錯的選擇;如果你希望最精簡的測試功能,Tape 將是你的最愛。