單元測試:開篇明義
一個單元測試是一段自動化的程式碼,這段程式碼呼叫被測試的工作單元,之後對這個單元的單個最終結果的某個假設進行檢驗。單元測試幾乎都是用單元測試框架編寫的。單元測試容易編寫,能快速執行。單元測試可靠、可讀,並且可維護。一個工作單元可以小到只包含一個方法,也可以大到包括實現某個功能的多個類和函式。
作為開發人員,或多或少,都在某種程度上進行過單元測試,比如,寫完程式碼在提交之前自己先測試下。也許你是用一個控制檯來呼叫一個函式進行測試,也是是特意建立介面程式來檢查某個元件的功能,或是乾脆在實際應用程式中進行各種手工操作。最終的結果都是讓你能在一定程度上確信程式碼工作正常,可以移交給他人。
這樣的單元測試方法,有以下幾個缺點:
- 單元測試程式碼難於維護,甚至當時測完就被刪了,即使有保留,也會經常發現以前(或一個月前、或一年前)寫的測試程式碼無法執行;
- 一個人寫的單元測試,無法共享給團隊裡其他人執行。
- 無法一鍵執行寫過的所有單元測試。
- 無法在幾分鐘內跑完所有單元測試。
- 無法在幾分鐘內快速新建一個基本單元測試。
要解決這些問題,可以:
- 使用單元測試框架編寫單元測試;
- 視單元測試程式碼跟產品程式碼同樣重要,也要納入版本管理,跟隨產品程式碼一起維護。
- 好的單元測試規範,學習他人總結的最佳實踐,能讓事半功倍。
一個優秀單元測試應具有如下特質:
- 它應該是自動化的,可重複執行;
- 它應該用一個單元測試框架編寫;
- 它應該容易實現;
- 它應該執行速度很快;
- 團隊任何人都可以一鍵執行它;
- 它應該是完全隔離的(獨立於其他測試的執行);
- 如果失敗了,應該很容易發現什麼是期待的結果,進而定位問題所在。
單元測試框架
單元測試框架是一個專門用於編寫、執行和檢視單元測試及其結果的框架,單元測試框架向開發人員提供進行單元測試的程式碼庫和模組。
基本上每一種常用的程式語言都有一個單元測試框架,通常單元測試框架都以它們支援的語言的開頭字母加上Unit作為名字,它們統稱為xUnit框架。C語言的單元測試框架是CUnit,C++的是CppUnit,Java的是JUnit,.NET的是NUnit,Python的是PyUnit。不是所有的單元測試框架都這麼命名,但大部分如此。
某些程式語言直接支援單元測試,他們的語法允許直接進行單元測試的宣告而不需要匯入第三方庫,比如C#、D語言。
更多的單元測試框架可參閱(需翻牆): List of unit testing frameworks
單元測試誰完成
除非有明確的分工,否則單元測試往往是由程式設計師自己來完成,最終受益的也是程式設計師自己。可以這麼說,程式設計師有責任編寫功能程式碼,同時也就有責任為自己的程式碼編寫單元測試。執行單元測試,就是為了證明這段程式碼的行為和我們期望的一致。
什麼時候開始單元測試
千萬不要等到專案後期再進行單元測試,那樣就失去檢查程式碼、預防缺陷的意義了。
很多人覺得為軟體編寫單元測試的最佳時機是軟體編碼完成以後,但是越來越多的人選擇在產品程式碼編寫之前寫單元測試,這種方法稱之為測試驅動開發(Test-Driven Development,TDD)。這是一種不同於傳統軟體開發流程的新型的開發方法,它要求在編寫某個功能的程式碼之前先編寫測試程式碼,然後編寫功能程式碼使測試通過,通過測試來推動整個開發的進行。
說到TDD,就不得不提到極限程式設計(ExtremeProgramming,簡稱XP),TDD是極限程式設計中的一個重要組成部分。Kent Beck先生最早在其極限程式設計方法論中,向大家推薦“測試驅動”這一最佳實踐,還專門撰寫了《測試驅動開發》一書,詳細說明如何實現。經過幾年的迅猛發展,測試驅動開發已經成長為一門獨立的軟體開發技術,其名氣甚至蓋過了極限程式設計。
有人將TDD和蓋房子進行類比,讓我印象深刻:
蓋房子的時候,工人師傅砌牆,會先用樁子拉上線,以使磚能夠壘的筆直,因為壘磚的時候都是以這根線為基準的。TDD就像這樣,先寫測試程式碼,就像工人師傅先用樁子拉上線,然後編碼的時候以此為基準,編寫出符合這個測試的功能程式碼,通過測試來推動整個開發的進行。
對單元測試的質疑
目前,在國內眾多中小型IT公司眾,鮮有將單元測試作為一種文化融入研發組織,做的好更是寥寥。應該來說是從意識形態上對單元測試的重視度不夠,也許未來會慢慢改變。
如果要在組織中引入單元測試,往往會遇到很多質疑。其中質疑最嚴重的聲音是:單元測試會不會給專案增加時間!
公司老闆、團隊領導者、專案經理和客戶通常是最關注時間的人,這幫人也是專案的關鍵人、決策人,不說服這些人,將很難再專案中引入單元測試。
沒錯,單元測試確實會增加開發功能所需的時間,但是單元測試提升了程式碼質量。專案中整體程式碼質量的提高,可以縮短後續專案維護時間(主要是通過可維護性和容易修護缺陷實現的),從而縮短產品的交付週期。
更多的質疑和回答,可以參考《單元測試的藝術(第2版)》中的9.5章節,裡面描述的很詳盡。
相關文章
- go 單元測試進階篇Go
- 第 15 篇:介面的單元測試
- 測試 之Java單元測試、Android單元測試JavaAndroid
- 摒棄無意義的單元測試
- 單元測試:單元測試中的mockMock
- Java Junit單元測試(入門必看篇)Java
- 通義靈碼實踐教程——單元測試
- 測試開發之單元測試-禪道結合ZTF驅動單元測試執行
- Laravel 測試驅動開發 -- 正向單元測試Laravel
- 單元測試,只是測試嗎?
- 單元測試-【轉】論單元測試的重要性
- 開發必備之單元測試
- golang單元測試Golang
- 單元測試真
- iOS 單元測試iOS
- python 單元測試Python
- 前端單元測試前端
- Flutter 單元測試Flutter
- 單元測試 Convey
- 單元測試工具
- 聊聊單元測試
- 十五、單元測試
- Go單元測試Go
- SpringBoot單元測試Spring Boot
- 前端測試:Part II (單元測試)前端
- SpringBoot-16-之整合MyBatis-xml篇+單元測試Spring BootMyBatisXML
- .net持續整合sonarqube篇之 sonarqube整合單元測試
- .net持續整合單元測試篇之單元測試簡介以及在visual studio中配置Nunit使用環境
- Junit單元測試—MavenMaven
- 單元測試框架 mockito框架Mockito
- 單元測試與MockitoMockito
- Source Generator 單元測試
- 單元測試?即刻搞定!
- 聊聊前端單元測試前端
- 單元測試基礎
- JavaScript單元測試框架JavaScript框架
- 單元測試 -- mocha + chaiAI
- React元件單元測試React元件