單元測試第二彈——單元測試與單元測試框架
一、黑盒測試與白盒測試
在***彈中(《單元測試***彈——從軟件開發(fā)生命周期談單元測試》)我們介紹過,軟件的測試包含單元測試、集成測試、系統(tǒng)測試和回歸測試四個階段。那么,這里我們先來看下各個階段都使用怎樣的測試方法。
軟件測試,從測試方法上來區(qū)分可以分為黑盒測試、白盒測試和灰盒測試。
1. 黑盒測試
黑盒測試,也稱為功能測試。測試者不了解程序的內(nèi)部情況,不需具備應用程序的代碼、內(nèi)部結構和編程語言的專門知識。只知道程序的輸入、輸出和系統(tǒng)的功能,這是從用戶的角度針對軟件界面、功能及外部結構進行測試,而不考慮程序內(nèi)部邏輯結構。測試案例是依應用系統(tǒng)應該做的功能,照規(guī)范、規(guī)格或要求等設計。測試者選擇有效輸入和無效輸入來驗證是否正確的輸出。 此測試方法可適合大部分的軟件測試,如集成測試以及系統(tǒng)測試。
黑盒測試主要是為了發(fā)現(xiàn)以下幾類錯誤:
- 是否有不正確或遺漏的功能?
- 在接口上,輸入是否能正確的接受?能否輸出正確的結果?
- 是否有數(shù)據(jù)結構錯誤或外部信息(例如數(shù)據(jù)文件)訪問錯誤?
- 性能上是否能夠滿足要求?
- 是否有初始化或終止性錯誤?
2. 白盒測試
白盒測試又稱透明盒測試、結構測試等。測試應用程序的內(nèi)部結構或運作,而不是測試應用程序的功能(即黑盒測試)。在白盒測試時,以編程語言的角度來設計測試案例。測試者輸入數(shù)據(jù)驗證數(shù)據(jù)流在程序中的流動路徑,并確定適當?shù)妮敵?,類似測試電路中的節(jié)點。測試者了解待測試程序的內(nèi)部結構、算法等信息,這是從程序設計者的角度對程序進行的測試。 白盒測試可以應用于單元測試、集成測試和系統(tǒng)的軟件測試流程。
白盒測試主要是想對程序模塊進行如下檢查:
- 對程序模塊的所有獨立的執(zhí)行路徑至少測試一遍。
- 對所有的邏輯判定,取“真”與取“假”的兩種情況都能至少測一遍。
- 在循環(huán)的邊界和運行的界限內(nèi)執(zhí)行循環(huán)體。
- 測試內(nèi)部數(shù)據(jù)結構的有效性,等等。
3. 灰盒測試
灰盒測試,是介于白盒測試與黑盒測試之間的一種測試,灰盒測試多用于集成測試階段,不僅關注輸出、輸入的正確性,同時也關注程序內(nèi)部的情況?;液袦y試不像白盒那樣詳細、完整,但又比黑盒測試更關注程序的內(nèi)部邏輯,常常是通過一些表征性的現(xiàn)象、事件、標志來判斷內(nèi)部的運行狀態(tài)。
4. 對代碼做白盒測試
上面介紹了軟件測試中的黑盒、白盒和灰盒測試。白盒測試被廣泛的使用在單元測試階段。
這里我們先來分析下,我們要進行單元測試,需要做哪些事情?因為單元測試的主要手段是白盒測試,白盒測試的測試方法是:測試者輸入數(shù)據(jù)驗證數(shù)據(jù)流在程序中的流動路徑,并確定適當?shù)妮敵?。那么整個測試流程大概需要包含以下幾個步驟:
- 初始化測試環(huán)境、準備測試數(shù)據(jù)。
- 調(diào)用需要被測試的單元。
- 收集結果,并與期望值比較。
- 測試數(shù)據(jù)清理。
以上四個步驟在每個單元在被測試的時候都需要被執(zhí)行。舉個例子,我們有一個除法運算的方法,我們要對他做單元測試。
- public class Calculator{
- public float divide(float divisor,float dividend){
- return divisor/dividend;
- }
- }
我們要在程序中驗證上面這個方法的正確性,一般會寫以下代碼來測試他:
- public class CalculatorTest{
- public static void main(String [] args){
- Calculator calculator = new Calculator();
- float result = calculator. divide(10.0,2.0);
- if(result == 5.0){
- System.out.println("divide test ok");
- }else{
- System.out.println("divide test failed");
- }
- }
- }
這只是對該方法測試的***個測試,如果我想測試這個方法在被除數(shù)是0的情況下會怎么樣,那么我就要再寫一個CalculatorTest2,然后重寫寫一個main方法,再重新定義一個Calculator對象,然后在調(diào)用divide方法的時候把第二個參數(shù)的值傳為0。
其實上面的測試是存在很大問題的,因為在內(nèi)存中并無法精確的存儲浮點數(shù),當我們把兩個浮點數(shù)相除的時候結果并不一定可以精確的存儲下來,而我們的逾期結果卻是一個精確值,這樣的比較可能會不相等的。但是這樣的情況需要多個case才有可能被發(fā)現(xiàn)。
所以,我們在測試一個類中的一個方法的時候,可能要定義大量的類,然后需要分別執(zhí)行,并且通過看控制臺的輸出才能確認結果。
這里,請先記住這些問題,因為,接下來我們要介紹的測試框架會幫我們解決這些問題的。
二、單元測試框架
通常,在沒有特定框架支持下,我們在對一個方法進行單元測試的時候,無外乎是使用分支判斷、異常處理、流程控制等來控制代碼的執(zhí)行,通過程序輸出來表示方法的執(zhí)行成功和失敗。這樣存在的***問題就是我們每執(zhí)行完一個單測之后,都要去控制臺看輸出才知道單元測試有沒有成功,這明顯是不合理的,因為單元測試是需要自動化執(zhí)行的,程序沒辦法幫我們檢查輸出是否正確的。
單元測試框架就解決了這個問題,一旦使用了框架,加入單元測試相對來說會簡單許多。通常,Java中常用的單元測試框架一般包含三個功能:測試工具、測試套件、測試運行器。
1. 測試工具
測試工具是一整套固定的工具用于基線測試。測試工具的目的是為了確保測試能夠在共享且固定的環(huán)境中運行,因此保證測試結果的可重復性。一般負責初始化測試環(huán)境、準備測試數(shù)據(jù)和測試數(shù)據(jù)清理。
2. 測試套件
測試套件意味捆綁幾個測試案例并且同時運行。
3. 測試運行器
用于執(zhí)行測試案例。一般負責調(diào)用需要被測試的單元、收集結果、并與期望值比較。
除了以上這些功能之外,針對不同的功能,一般還會提供很多API和語法支持。
下一彈會重點介紹如何使用JUnit進行單元測試—《單元測試第三彈——使用JUnit進行單元測試》
【本文是51CTO專欄作者Hollis的原創(chuàng)文章,轉載聯(lián)系作者本人獲取授權】