天天看點

路徑覆寫和基本路徑覆寫

從測試方法會不會關注程式内部的結構可以将其劃分為白盒測試和黑盒測試以及灰盒測試,黑盒測試不關注程式内部的實作結構,僅僅是通過向程式進行輸入來觀察程式的輸出對不對;白盒測試就需要關注程式内部的實作結構,對程式的代碼邏輯結構實施相關的測試;下面來簡單介紹一下路徑覆寫法和基本路徑覆寫法兩種白盒測試方法。

路徑覆寫法

路徑覆寫法是通過測試代碼中的每個可能路徑來檢查代碼的每個部分是否按照預期工作。路徑覆寫法要求測試用例覆寫每個可能的路徑,包括所有可能的循環和分支情況。這種方法需要編寫大量的測試用例來覆寫所有可能的路徑,是以它往往比較費時和費力。

接下來以一段代碼作為測試對象:

public static int test(int a,int b,int c) {
1         int result = 0;
2         if(a == 0 or b > 2) {
3             result = b - a;
          }
4         if(a > 0 and c > 0 ) {
5             result = c * a;
        }
6        return result;
    }           

使用路徑覆寫法設計測試用例

第 1 步:分析待測代碼,畫出程式的流程圖。上述代碼的參考流程圖如下所示,為了友善分析路徑,圖中紅色字母 A、B、C、D 辨別出了每個判斷語句的分支:

路徑覆寫和基本路徑覆寫

流程圖

第 2 步:分析流程圖

從上圖中可以看出,這段代碼共有 2 個判斷語句,每個判斷語句分别有取真值、取假值兩個分支。那麼,程式中共有如下四條路徑:

  • 路徑 1 :A - C
  • 路徑 2 :A - D
  • 路徑 3 :B - C
  • 路徑 4 :B - D

第 3 步:編寫測試用例。

根據路徑覆寫的定義,我們需要設計一些測試用例,使程式中的每個路徑至少被執行一次。是以,我們可以設計如下表中的四個測試用例來覆寫這四條路徑。

測試用例編号 輸入資料 預期結果 路徑覆寫情況
testcase_01 a = -2 , b = 1 , c = 9 result = 0 路徑 1 :A - C
testcase_02 a = 5 , b = -2 , c = 3 result = 15 路徑 2 :A - D
testcase_03 a = 0 , b = 3 , c = 3 result = 3 路徑 3 :B - C
testcase_04 a = 1 , b = 5 , c = 9 result = 9 路徑 4 :B - D

綜上所述,路徑覆寫可以使程式中的每一條路徑都經過測試,確定程式執行路徑的正确性。但是,對于判斷語句多且複雜、循環次數多的程式,需覆寫的路徑數量可能非常龐大,無法在短時間内測試完,例如,下圖是一段代碼的流程圖,圖中含有多個判斷語句、循環語句,如果要将所有路徑都測試到,将花費大量的時間,是以,在實際的項目測試中基本不可能把所有路徑都覆寫到。

路徑覆寫和基本路徑覆寫

複雜流程圖

基本路徑覆寫法

路徑覆寫可以使程式中的路徑都被測試到,但是,要對程式中的路徑做到完全覆寫經常是無法實作的。為了解決這一難題,我們需要在保證測試品質的前提下把測試的路徑數量壓縮到一定的範圍内,基礎路徑覆寫法正好可以解決該問題。

基本路徑覆寫法是在程式控制流圖的基礎上,通過分析控制結構的圈複雜度,導出基本可執行的路徑集合設計測試用例,運作被測程式,使程式的基本路徑都得到覆寫。基本路徑覆寫法把測試時需要覆寫的路徑壓縮到一定的範圍内,使程式中的每一個可執行語句都至少執行一次,程式中的循環體最多隻執行一次。

為了友善比較,仍以上述代碼作為測試對象,使用基本路徑覆寫法來設計白盒測試用例,基本步驟如下:

第 1 步:分析待測試代碼,畫出程式的流程圖(和路徑覆寫法中流程圖一樣),如果對該方法比較熟練或對程式流程比較清晰,可省略這個步驟。

我們知道,在控制流圖中如果含有複合條件,需要改為單條件嵌套的形式。為了後續的講述更加清晰,這裡先把上述流程圖中的複合條件按控制流圖的要求進行拆分,具體如下:

路徑覆寫和基本路徑覆寫

單條件嵌套流程圖

第 2 步:根據流程圖畫出控制流圖。

在控制流圖中,圓形符号 ○ 稱為“節點”,表示一個基本的代碼塊;包含條件的節點稱為 “ 判斷節點 ” ;箭頭稱為 “ 邊 ”,表示控制流路徑,反向邊則表示可能存在循環。按照控制流圖的規則,上述流程圖可以畫成下面的控制流圖:

路徑覆寫和基本路徑覆寫

程式的基本控制流圖

第 3 步:計算圈複雜度。

圈複雜度 V(G) 有三種計算方法,下面簡單介紹一下用 3 種方法計算本例的圈複雜度:

方法一:V(G) = A + 1,其中 A 代表控制流圖中的封閉區域數量。從下圖可以看出,程式的控制流圖中共有 4 個封閉區域,是以,圈複雜度 V(G) = 4 + 1 = 5 。

路徑覆寫和基本路徑覆寫

程式控制流圖

方法二:V(G) = P + 1,其中 P 代表控制流圖中的判定節點數。從下圖可以看出,程式的控制流圖中共有 4 個判定節點,是以,圈複雜度 V(G) = 4 + 1 = 5 。

路徑覆寫和基本路徑覆寫

程式的控制流圖

方法三:V(G) = e - n + 2,其中 e 代表控制流圖中的邊的數量,即控制流中的箭頭數量;n 代表控制流圖的節點數量,即控制流圖中的圓圈數量。從下圖中可以看出,程式的控制流圖中有 11 條邊(11 個箭頭),8 個節點(8 個圓圈),是以,圈複雜度 V(G) = 11 - 8 + 2 = 5 。

路徑覆寫和基本路徑覆寫

程式控制流圖

第 4 步:确定基本路徑的集合。

基本路徑又稱為獨立路徑,是指至少包含一條其他獨立路徑中未包含的路徑。例如,在上圖中,路徑 1 - 2 - 3 - 5 - 8 是一條基本路徑,1 - 2 - 4 - 3 - 5 - 8 則可以看成了另外一條基本路徑,因為這條路徑中經過 4 節點的路徑在第一條基本路徑中未包含。

圈複雜度是指程式中的獨立路徑數量,是確定程式中每個可執行語句至少執行一次需要的測試用例數量的最小值。根據第 3 步的計算結果,本例中我們需要确定 5 條基本路徑,具體如下:

  • 路徑 1 :1 - 2 - 3 - 5 - 8
  • 路徑 2 :1 - 2 - 4 - 3 - 5 - 8
  • 路徑 3 :1 - 2 - 4 - 5 - 8
  • 路徑 4 :1 - 2 - 4 - 5 - 6 - 8
  • 路徑 5 :1 - 2 - 4 - 5 - 6 - 7 - 8

第 5 步:根據基本路徑編寫測試用例。

根據基本路徑覆寫法的定義,我們需要設計測試用例分别覆寫第 4 步中的 5 條基本路徑,即設計合理的輸入資料使程式運作時經過指定的路徑。是以,我們可以設計如下表中的 5 個測試用例來覆寫這 5 條基本路徑。

測試用例編号 輸入資料 預期結果 路徑基本覆寫情況
testcase_01 a = 0 , b = 1 , c = 9 result = 1 路徑 1
testcase_02 a = 0 , b = 3 , c = 5 result = 3 路徑 2
testcase_03 a = -2 , b = 1 , c = 3 result = 0 路徑 3
testcase_04 a = 1 , b = 0 , c = -1 result = 0 路徑 4
testcase_05 a = 5 , b = -3 , c = 2 result = 10 路徑 5

綜上所述,使用基本路徑覆寫法設計用例進行測試時,可以使程式中的每條獨立路徑都至少執行一次。如果程式中的基本路徑達到了 100% 覆寫,則分支(判定)覆寫、條件覆寫也能達到 100% 覆寫。如果使用基本路徑覆寫法後程式中仍有未覆寫到的路徑,可使用邏輯覆寫法補充測試用例保證覆寫全面。

在本案例中,基本路徑法設計出的測試用例反而比路徑法多一條,那是因為二者的覆寫方法不一樣導緻的,如果是在有組合關系或者循環邏輯的代碼中,基本路徑法就會簡單很多。