在軟件單元測試時,考慮到軟件單元的所有情況有時是非常困難的。能不能采取一些有效的辦法,能夠在可接受的單元測試用例數(shù)量的前提下,提高測試的有效性呢?本文對常用的單元測試用例設(shè)計方法進行介紹,期待對大家有一定的借鑒作用。
1、等價類劃分(Equivalence Class Partitioning)
等價類劃分法將程序所有可能的輸入數(shù)據(jù)和輸出(有效的和無效的)劃分成若干個等價類,然后從每個等價類中選取具有代表性的數(shù)據(jù)作為測試用例,從而保證測試用例具有完整性和代表性。
形成測試區(qū)間的數(shù)據(jù)不只是函數(shù)/過程的參數(shù),也可以是軟件可以訪問的全局變量,系統(tǒng)資源等,這些變量或資源可以是以數(shù)值,也可能是以其他形式存在,如狀態(tài)。
例1:計算絕對值的函數(shù)的設(shè)計說明如下:

根據(jù)輸入和輸出,可以劃分出如下的2個輸入的等價類和一個輸出的等價類:

針對該例子,我們可以設(shè)計以下2個測試用例:
1)Test Case1:輸入4,返回4,覆蓋 I1和O1
2)Test Case2:輸入-10,返回10,覆蓋I2和O1
2、邊界值分析(Boundary Value Analysis)
通常大量的錯誤發(fā)生在輸入或輸出范圍的邊界上,而不是發(fā)生在輸入輸出范圍的內(nèi)部。
邊界值分析法是對輸入或輸出的邊界值進行測試的一種方法,通常邊界值分析法是作為對等價類劃分法的補充,此時的測試用例通常來自等價類的邊界。
如例1的絕對值的例子中:

根據(jù)邊界值分析方法得出的測試用例有:
Test Case1 :輸入0,返回0
Test Case2 :輸入僅比0大的數(shù),返回輸入的正數(shù)
Test Case3 :輸入最大正實數(shù),返回輸入的正實數(shù)
Test Case4 :輸入僅比0小的數(shù),返回0-輸入的值
Test Case5 :輸入最小的負實數(shù),返回0-輸入的值
3、基本路徑測試(Basis Path Testing)
基本路徑測試法是在程序控制流圖的基礎(chǔ)上,通過分析控制構(gòu)造的圈復(fù)雜度,導出基本可執(zhí)行路徑集合,從而設(shè)計測試用例的方法。設(shè)計出的測試用例能夠保證程序的每個可執(zhí)行語句至少執(zhí)行一次。這種單元測試用例的方法首先要創(chuàng)建出程序的控制流圖,之后確定程序的圈復(fù)雜度,最后進行測試用例的設(shè)計。
3.1 創(chuàng)建出程序的控制流圖
程序的控制流程圖是描述程序控制流的一種圖示方法,與程序流程圖類似。程序控制流圖只有圓形和箭頭兩種圖形符號。圓形稱為控制流圖的一個結(jié)點,表示一個或多個無分支的語句或源程序語句;箭頭稱為邊或連接,代表控制流。需要注意的是,在創(chuàng)建程序的控制流圖時,如果判斷中的條件表達式是由一個或多個邏輯運算符(OR, AND)連接的復(fù)合條件表達式,則需要改為一系列只有單條件的嵌套的判斷。
如下面代碼的控制流圖:

3.2 計算圈復(fù)雜度
圈復(fù)雜度是一種度量程序邏輯復(fù)雜性的軟件度量指標,是程序的基本的獨立路徑數(shù)目,即為確保所有語句至少執(zhí)行一次的測試數(shù)量。根據(jù)程序控制流圖有以下三種計算方法:

a) 控制流圖中封閉區(qū)域的數(shù)量,其中圖所在的平面認為是一個區(qū)域
上圖的圈復(fù)雜度為3 (區(qū)域中的藍色部分)
b) 控制流圖中邊的數(shù)量減去結(jié)點數(shù)量+2
V(G) = E – N + 2
上圖中,圈復(fù)雜度為? : 7-6+2 = 3
c) 控制流圖中判定結(jié)點的數(shù)量+1
V(G) = P + 1
其中P為控制流圖中判定結(jié)點的數(shù)量
上圖判定結(jié)點為2個,因此圈復(fù)雜度為3
3.3 編寫測試用例
根據(jù)圈復(fù)雜度計算結(jié)果和程序控制流圖,得出獨立路徑數(shù)和相應(yīng)的獨立路徑。根據(jù)獨立的路徑,分別設(shè)計輸入條件數(shù)據(jù),使程序分別執(zhí)行到所有獨立路徑,即可得到相應(yīng)的測試用例。
如之前的數(shù)據(jù)流圖,根據(jù)圈復(fù)雜度,得出有3個獨立的路徑,根據(jù)相應(yīng)的獨立路徑,分別設(shè)計輸入條件,則可以確定3個測試用例:

Test Case1 :
執(zhí)行路徑: 1-2-6
輸入條件: C1 = 11? ;? C2任意
Test Case2 :
執(zhí)行路徑: 1-3-4-6
輸入條件: C1 = 8,? C2 = 8
Test Case3 :
執(zhí)行路徑: 1-3-5-6
輸入條件: C1 = 8,? C2 = 12
4、基于測試覆蓋度的測試用例設(shè)計
單元測試中,經(jīng)常還提到一個測試覆蓋度的概念,比如語句覆蓋、分支覆蓋等,也是一種單元測試用例的設(shè)計方法。具體可以參見楊老師的文章:談?wù)劀y試覆蓋度,在此不在贅述。
5、軟件設(shè)計說明導出的測試(Specification derived test)
我們按照以上所有的方法都進行了單元測試用例,我們的代碼就沒有問題了嗎?我們看下圖的例子。

我們應(yīng)用了所有上面提及的單元用例設(shè)計方法,但是可能仍然不能發(fā)現(xiàn)例子中的除以0的問題。因為我們之前的測試用例設(shè)計方法更多關(guān)注的是程序中的判斷表達式及表達式中的條件,即是否所有代碼都執(zhí)行過,而不是所有代碼都正確的執(zhí)行。所以,我們通常說的代碼覆蓋度實際上也被稱為代碼的結(jié)構(gòu)覆蓋度(Structural coverage),而不是需求邏輯的覆蓋。
因此,我們還需要考慮從需求/規(guī)格方面考慮的用例設(shè)計方法。對于單元測試來說,規(guī)格就是詳細設(shè)計。
軟件設(shè)計說明導出的測試用例,就是通過根據(jù)相關(guān)的軟件設(shè)計說明文檔進行設(shè)計,每個測試用例測試設(shè)計說明中一項或多項陳述。
如例1中,設(shè)計說明中有2個陳述,可以用以下2個測試用例來對應(yīng)。
Test Case 1:輸入4,返回4。? // 對應(yīng)第一個陳述
Test Case 2:輸入-10,返回10 // 對應(yīng)第二個陳述
例1:計算數(shù)的絕對值的函數(shù)的設(shè)計說明如下:

6、錯誤猜測 (Error Guessing)
錯誤猜測法就是根據(jù)經(jīng)驗猜想可能的錯誤,并依此設(shè)計測試用例的方法。錯誤猜測法只能作為測試設(shè)計的補充而不能單獨用來設(shè)計測試用例,否則可能會造成測試的不充分。
錯誤猜測法的基本思路:
列舉出程序中所有可能有的錯誤和容易發(fā)生錯誤的特殊情況,根據(jù)他們選擇測試用例,例如在單元測試時許多在模塊中常見的錯誤或以前產(chǎn)品測試中曾經(jīng)發(fā)現(xiàn)的錯誤等。
如之前的被除數(shù)為零的例子的情況。測試人員會根據(jù)算法中有除法運算,那么就可以推測出,至少需要考慮是否存在被除數(shù)為零的情況。
雖然說了這么多的測試用例設(shè)計方法,但這并不是所有。針對測試內(nèi)容的不同,可能還會有一些測試用例設(shè)計方法,如狀態(tài)轉(zhuǎn)換測試(State-transition Testing)等,這些測試用例設(shè)計方法適用于不同的情況下的測試,因此在這里不在介紹。
我們給出了這么多的測試用例設(shè)計方法,實際使用時,需要根據(jù)自己項目的情況選用恰當?shù)姆椒ㄟM行測試用例的開發(fā)。實際上,組合使用各種測試用例設(shè)計方法時,所設(shè)計出的測試用例是存在重復(fù)的情況,因此我們在進行單元測試用例設(shè)計時,還要恰當?shù)娜ブ?。那么,整個單元測試用例設(shè)計的過程到底是什么樣的呢?通常的流程如下,供大家參考:
1) 確定單元測試的策略
2) 設(shè)計正面測試(Positive Testing)測試用例
3) 設(shè)計負面測試(Negative Testing)測試用例
4) 設(shè)計覆蓋率測試用例,使測試用例滿足預(yù)定的覆蓋度要求
5) 設(shè)計需求中其他測試特性測試用例
6) 最后在測試執(zhí)行后,可能會需要對測試用例進行調(diào)整、補充,如測試覆蓋度沒有達到預(yù)期目標時