1.什么是單元測試(Unit Testing)?
測試(Testing)這個詞很容易理解,那么什么是單元(Unit)呢? 一個單元指的是應用程序中可測試的最小的一組源代碼。一組源代碼可測試,一般要求其有明確的輸入和輸出。因此,一般來講,源代碼中包含明確的輸入和輸出的 每一個方法被認為是一個可測試的單元。注意,這里指的輸出,並不局限於方法的返回值或對輸入參數的改變,而包括了方法的執行過程中,改變的任何數據。
單元在程序里可以簡單的理解為一個模塊,一個方法。單元測試也就是在完成每個模塊后都進行的測試。從確保每個模塊沒有問題,從而提高整體的程序質量。
2.單元測試的目的?
單元測試的目的,是將應用程序的所有源代碼,隔離成最小的可測試的單元,保證每個單元的正確性。理想情況下,如果每個單元都能保證正確,就能保證應用程序整體相當程度的正確性。
另一方面,單元測試也是一種特殊類型的文檔,相對於書面的文檔,測試腳本本身往往就是對被測試代碼的實際的使用代碼,對於幫助開發人員理解被測試單元的使用是相當有幫助的。
3.單元測試的手段
測試分為黑盒測試白盒測試。
黑盒測試:只知道WHAT下進行的測試,黑盒測試一般由測試人員進行。
單元測試是一種白盒測試,目的是驗證所設計的類是否符合需求。
在設計測試用例時,應當包括合理的輸入條件和不合理的輸入條件。
白盒測試:知道被測軟件如何(HOW)完成功能和完成什么樣的功能(WHAT),白盒測試一般由開發人員完成。
4.如何進行單元測試
1)隔離
要進行單元測試,首先就是要將被測試的單元,與所有外部依賴進行隔離。一般來講,進行隔離主要有兩種可選的技術,一種叫Stub,一種叫Mock。對於兩個的區別和取舍,Martin Fowler有一個很經典的文章:Mocks Aren't Stubs。簡單來說,如果要Stub或Mock一個方法,Stub指的是,為了測試,手動寫一個相同簽名的方法,根據我的測試需要,對給定的輸入參數,返回一定的輸出;而Mock則借助一定的框架組件,自動生成一個方法的實現,對於給定的輸入,返回一定的輸出。當然,所謂的Stub或Mock,並不單指對方法,尤其是在面向對象編程中,也可以是對屬性,對對象或者對接口,等等。
為了方便實現隔離,對軟件設計和開發的一個潛在的激勵是,軟件模塊的設計人員和開發人員,不得不時時思考,在當前語言支持的各種特性的條件下,如何使得所寫的代碼,能夠被方便的被隔離。雖然這看起來很像是一種限制,但是和軟件設計的SOLID原則,其實是不謀而合的,因此,也就未嘗不是一個優點了。
5.單元測試的內容
模塊接口測試:對通過被測模塊的數據流進行測試。為此,對模塊接口,包括參數表、調用子模塊的參數、全程數據、文件輸入/輸出操作都必須檢查。
局部數據結構測試:設計測試用例檢查數據類型說明、初始化、缺省值等方面的問題,還要查清全程數據對模塊的影響。
路徑測試:選擇適當的測試用例,對模塊中重要的執行路徑進行測試。對基本執行路徑和循環進行測試可以發現大量路徑錯誤。
錯誤處理測試:檢查模塊的錯誤處理功能是否包含有錯誤或缺陷。例如,是否拒絕不合理的輸入;出錯的描述是否難以理解、是否對錯誤定位有誤、是否出錯原因報告有誤、是否對錯誤條件的處理不正確;在對錯誤處理之前錯誤條件是否已經引起系統的干預等。
邊界測試:要特別注意數據流、控制流中剛好等於、大於或小於確定的比較值時出錯的可能性。對這些地方要仔細地選擇測試用例,認真加以測試。
此外,如果對模塊運行時間有要求的話,還要專門進行關鍵路徑測試,以確定最壞情況下和平均意義下影響模塊運行時間的因素。這類信息對進行性能評價是十分有用的。
6.單元測試的步驟
通常單元測試在編碼階段進行。在源程序代碼編制完成,經過評審和驗證,確認沒有語法錯誤之后,就開始進行單元測試的測試用例設計。利用設計文檔,設計可以驗證程序功能、找出程序錯誤的多個測試用例。對於每一組輸入,應有預期的正確結果。
模塊並不是一個獨立的程序,在考慮測試模塊時,同時要考慮它和外界的聯系,用一些輔助模塊去模擬與被測模塊相聯系的其它模塊。這些輔助模塊分為兩種:
驅動模塊:相當於被測模塊的主程序。它接收測試數據,把這些數據傳送給被測模塊,最后輸出實測結果。
樁模塊:用以代替被測模塊調用的子模塊。樁模塊可以做少量的數據操作,不需要把子模塊所有功能都帶進來,但不允許什么事情也不做。
如果一個模塊要完成多種功能,且以程序包或對象類的形式出現,例如Ada中的包,Modula中的模塊,C++中的類。這時可以將這個模塊看成由幾個小程序組成。對其中的每個小程序先進行單元測試要做的工作,對關鍵模塊還要做性能測試。對支持某些標准規程的程序,更要着手進行互聯測試。有人把這種情況特別稱為模塊測試,以區別單元測試。
6.測試的重要性
單元測試是軟件測試的基礎,因此單元測試的效果會直接影響到軟件的后期測試,最終在很大程度上影響到產品的質量。從如下幾個方面就可以看出單元測試的重要性在何處。
時間方面:如 果認真的做好了單元測試,在系統集成聯調時非常順利,因此會節約很多時間,反之那些由於因為時間原因不做單元測試或隨便做做的則在集成時總會遇到那些本應 該在單元測試就能發現的問題,而這種問題在集成時遇到往往很難讓開發人員預料到,最后在苦苦尋覓中才發現這是個很低級的錯誤而在悔恨自己時已經浪費了很多 時間,這種時間上的浪費一點都不值得,正所謂得不償失。
測試效果:根 據以往的測試經驗來看,單元測試的效果是非常明顯的,首先它是測試階段的基礎,做好了單元測試,在做后期的集成測試和系統測試時就很順利。其次在單元測試 過程中能發現一些很深層次的問題,同時還會發現一些很容易發現而在集成測試和系統測試很難發現的問題。再次單元測試關注的范圍也特殊,它不僅僅是證明這些 代碼做了什么,最重要的是代碼是如何做的,是否做了它該做的事情而沒有做不該做的事情。
測試成本:在單元測試時某些問題就很容易發現,如果在后期的測試中發現問題所花的成本將成倍數上升。比如在單元測試時發現1個問題需要1個小時,則在集成測試時發現該問題需要2個小時,在系統測試時發現則需要3個小時,同理還有定位問題和解決問題的費用也是成倍數上升的,這就是我們要盡可能早的排除盡可能多的bug來減少后期成本的因素之一。
產品質量:單元測試的好與壞直接影響到產品的質量,可能就是由於代碼中的某一個小錯誤就導致了整個產品的質量降低一個指標,或者導致更嚴重的后果,如果我們做好了單元測試這種情況是可以完全避免的。
綜上所述,單元測試是構築產品質量的基石,我們不要因為節約單元測試的時間不做單元測試或隨便做而讓我們在后期浪費太多的不值得的時間,我們也不願意因為由於節約那些時間導致開發出來的整個產品失敗或重來!
7.如何寫好測試代碼的Guidelines:
1)有測試總比沒測試好
2)測試盡可能的小而快
3)使測試自動化
4)進行代碼覆蓋檢測
5)在寫任何新的實現代碼或測試代碼之前,先修復所有運行失敗的測試
6)再簡單的代碼也需要測試
7)特別注意輸入參數的邊界案例
8)不要只測試正常流程,還要測試可選和例外流程
9)對於每一個報告的Bug,寫一個對應的測試用例,方便回歸測試
10)時刻注意,所有測試都通過,不代表程序就真的100%沒問題,測試永遠只是輔助
