代碼覆蓋

**代碼覆蓋**（英語：**Code coverage**）是軟體測試中的一種度量，描述程式中原始碼被測試的比例和程度，所得比例稱為**代碼覆蓋率**。 

代碼覆蓋是由系統化軟體測試所衍生的方式。第一份出版的相關參考資料是 Miller 及 Maloney1963 年在 ACM 通訊上發表的論文 。

代碼覆蓋是飛行裝置進行安全認證中的考量項目之一。飛行裝置相關認證的指南列在美國聯邦航空管理局的檔案 DO-178B 及 DO-178C。
功能安全標準，如 IEC 61508 或 ISO 26262，並未定義程式碼覆蓋率之需求值，只列為軟體測試方法的選項，唯有航太產業標準（DO-178B）要求 100%，以因應超高可靠度的產品需求，此數值對於工業或汽車產品實屬理想目標。

## 覆蓋率準則

為了量測測試套件測試軟體的程度，會用一種或多種不同的覆蓋率準則。

### 基本的覆蓋率準則

以下列出一些基本的覆蓋率準則：

* 函式覆蓋率（Function coverage）：程式中的每個函式（或副程式）都被呼叫了嗎？
* 語句覆蓋率（Statement coverage）：程式中的每條語句都被執行了嗎？
* 邊覆蓋率（Edge coverage）：若用控制流圖表示程式，控制流圖中的每個邊都被執行了嗎？
  * 分支覆蓋率（Branch coverage）：每個控制結構中（例如 if 和 case 語句）的每個分支（也稱為決策到決策路徑）是否均被執行？例如，給定一個 if 語句，其 true 和 false 分支是否均被執行？（此為邊覆蓋率的子集）
* 條件覆蓋率（Condition coverage）：也稱為謂詞覆蓋率（predicate coverage），每一個布林子表達式是否均被取過真值和假值？

考慮以下的 C++ 函式：

假設此函式是一個大型程式的一部份，且某測試用例執行到此函式：

* 函式覆蓋率：只要函式 foo 有執行過一次，即滿足函式覆蓋率 100% 的條件。
* 語句覆蓋率：若有呼叫過 `foo(1,1)`，函式中每一行（包括 `z = x;`）都執行一次，滿足語句覆蓋率 100% 的條件。
* 分支覆蓋率：若有呼叫過 `foo(1,1)` 及 `foo(0,1)`，前者會使 `if` 的條件成立，因此 `z = x;` 會執行，後者會使 `if` 的邏輯運算式（`(x>0) && (y>0);`）不成立，因此滿足分支覆蓋率 100% 的條件。
* 條件覆蓋率：若有呼叫過 `foo(1,1)`、`foo(1,0)` 及 `foo(0,0)`，前二個會使 `(x>0)` 的條件成立，而第三個會使該條件不成立，而第一個會使 `(y>0)` 的條件成立，而後面二個會使該條件不成立，所有條件都有出現成立及不成立的情形，因此滿足條件覆蓋率 100% 的條件。

考慮以下的程式：

以下二個測試可以得到 100% 的條件覆蓋率：

* `a=true`, `b=false`
* `a=false`, `b=true`

但上述的測試條件都不會使 if 的邏輯運算式成立，因此不符合分支覆蓋的條件。

有時會需要用錯誤插入的方式來確保所有條件及例外處理程式都有一定的覆蓋率。

### 修改條件 / 判斷覆蓋

在一些安全關鍵應用（例如飛航用的軟體）中，一般會需要滿足修改條件 / 判斷覆蓋（modified condition/decision coverage，簡稱 MC/DC）的準則。此準則是條件 / 判斷覆蓋的延伸，而且每個條件都要可以獨立影響判斷結果的成立或不成立。例如考慮以下的程式：

以下的測試可滿足條件 / 判斷覆蓋：

* a=true, b=true, c=true
* a=false, b=false, c=false

不過，若第一項測試中 b 的值改為 false，不影響判斷結果，第二項測試中 c 的值改為 true，不影響判斷結果，因此需要用以下的測試才能滿足修改條件 / 判斷覆蓋：

* a=**false**, b=**false**, c=true
* a=**true**, b=false, c=**true**
* a=false, b=**true**, c=**true**
* a=true, b=true, c=**false**

其中粗體的條件表示是會影響判斷結果的條件，在影響判斷結果的條件中，每個變數都出現至少二次，其中至少一次其值為真，至少一次其值為假。

### 多重條件覆蓋

此覆蓋率準則要求要測試邏輯運算式中的所有組合，例如上述程式的多重條件覆蓋需要有以下的 8 個測試：

* a=false, b=false, c=false
* a=false, b=false, c=true
* a=false, b=true, c=false
* a=false, b=true, c=true
* a=true, b=false, c=false
* a=true, b=false, c=true
* a=true, b=true, c=false
* a=true, b=true, c=true

### 其他覆蓋率準則

以下也是一些可能會用到的覆蓋率準則：

* LCSAJ 覆蓋率：是否執行過每一個 LCSAJ（線性代碼序列和跳轉）？
* JJ 路徑覆蓋率（JJ-Path coverage）：是否執行過每一個 JJ 路徑（從跳轉到跳轉之間的路徑，也就是 JCSAJ）？
* 路徑覆蓋率（Path coverage）：是否執行過程式中所有可能的路徑？
* 進入點 / 結束點覆蓋率（Entry/exit coverage）**：是否執行過函式中所有可能的進入點及結束點？**
* 迴圈覆蓋率（Loop coverage）：所有迴圈是否都有執行過零次、一次及一次以上的測試？
* 參數值覆蓋率（Parameter Value Coverage）：對於一個方法的所有參數，是否有執行過其中最常見的數值？

安全關鍵應用一般會要求某種特定的覆蓋率要到達 100%。

有些覆蓋之間有相關性：例如路徑覆蓋就包括了判斷覆蓋、指令覆蓋及進入點 / 結束點覆蓋，而判斷覆蓋也包括了指令覆蓋。

完整的路徑覆蓋測試多半難以實現甚至不可能實現。有 $n$ 個判斷的程式就會有 $2^{n}$ 種完整路徑，迴圈結構可能會產生無窮種完整路徑。程式中的許多路徑也許是不可行的，因為也許沒有受測系統的輸入，使系統完整依某特定路徑執行。而且已證實沒有識別不可行路徑的通用演算法（若有，此演算法就可以求解停機問題）。實務上路徑覆蓋測試的軟體只會試圖找出隨著迴圈執行次數不同時，有變動的路徑，設法找到「基本路徑」，並要求對基本路徑需達到路徑覆蓋的要求。

## 實務

目標軟體是在特定環境下配合特定的選項或函式庫所建立，所執行的每一個函式都會對應到原代碼的機能點，代碼覆蓋的程式可以讓程式開發者及品質保證單位可以找出程式在正常情形下不會執行或是很少執行的部份（例如異常處理程式），也幫助測試工程師確認最重要的條件（機能點）是否有測試到。測試結果可進行分析，確認哪一部份程式尚未執行到，後續再修改測試程式，對這部份進行必要的測試。上述作法的目的是為了開發一套嚴格且可管理的回歸測試。

在配合軟體開發環境進行代碼覆蓋率時，需考慮以下的事項：

* 軟體的需要哪一種代碼覆蓋？其覆蓋要求率為何？依嚴格程度來看：依序為指令覆蓋、條件 / 判斷覆蓋、修改條件判斷覆蓋及 LCSAJ 覆蓋，越後面的越嚴格。
* 會利用測試時量測到的代碼覆蓋率來確認受測系統達到哪些需求嗎（DO-178B）？
* 目的碼是否可以追溯到原代碼的指令？若無法追溯到原代碼，DO-178B A 等級的認證會要求在組合語言層級的代碼覆蓋。「需在目的碼層級進行額外的驗證．以確認產生目的碼的正確性」（DO-178B para-6.4.4.2）

測試工程師可以根據代碼覆蓋測試的報告來調整測試用例、輸入或是組態，以增加重要機能的代碼覆蓋率。測試工程師常常會使用到指令覆蓋及判斷覆蓋，前者會報告在測試中會執行到多少比例的程式碼，後者會報告在測試中會執行到多少比例的的判斷結果，二者都會輸出一個覆蓋率的度量，以百分比表示。其意義則需視進行的代碼覆蓋種類來決定，67% 的判斷覆蓋率會比 67% 的指令覆蓋率會來得全面。

一般而言代碼覆蓋工具及函式庫會影響程式效能，也會消耗記憶體或其他資源，無法在系統正常使用時測試。因此一般只在開發階段進行，提供給客戶的系統不會包括代碼覆蓋工具及函式庫。也有一些軟體無法用覆蓋測試來測試，其覆蓋率會用分析的方式來得到近似值，而不是用直接測試到的結果。

有一些缺陷會受到代碼覆蓋工具的影響，像在進行代碼覆蓋測試時，可以略過一些有競爭危害或是實時敏感度高的程式。相對的，當加上額外的代碼覆蓋測試碼時，也可能比較容易找到這類的缺陷。

## 相關條目

* 循環複雜度
* 智慧型驗證
* 線性代碼序列和跳轉
* 修改條件判斷覆蓋
* 突變測試
* 回歸測試
* 軟體度量
* 靜態程式分析
* 白盒測試
* 功能安全

## 參考資料

## 外部連結

* Branch Coverage for Arbitrary Languages Made Easy（頁面存檔備份，存於網際網路檔案館）
* Code Coverage Analysis（頁面存檔備份，存於網際網路檔案館） by Steve Cornett
* Code Coverage Introduction（頁面存檔備份，存於網際網路檔案館）
* 開放式目錄計劃中和 Development Tools (Java) 代碼覆蓋率相關的內容
* 開放式目錄計劃中和 Development Tools (General) 代碼覆蓋率相關的內容
* FAA CAST Position Papers（頁面存檔備份，存於網際網路檔案館）
* Gcov（頁面存檔備份，存於網際網路檔案館） with graphical summaries LCOV（頁面存檔備份，存於網際網路檔案館） and text/XML summaries gcovr