代碼覆蓋率

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

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

代碼覆蓋是飛行設備進行安全認證中的考量項目之一。飛行設備相關認證的指南列在美国联邦航空管理局的文件及。
功能安全標準，如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++函式：

```cpp
int foo (int x, int y)
{
    int z = 0;
    if ((x>0) && (y>0)) {
        z = x;
    }
    return z;
}
```


假設此函式是一個大型程式的一部份，且某測試用例執行到此函式：
* 函式覆蓋率：只要函式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%的條件。

考慮以下的程式：

```pascal
if a and b then
```

以下二個測試可以得到100%的條件覆蓋率：
* `a=true`, `b=false`
* `a=false`, `b=true`
但上述的測試條件都不會使if的邏輯運算式成立，因此不符合分支覆蓋的條件。

有時會需要用的方式來確保所有條件及异常处理程式都有一定的覆蓋率。

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

```pascal
if (a or b) and c then
```

以下的測試可滿足條件/判斷覆蓋：
* 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 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
* 
* 
* FAA CAST Position Papers
* Gcov with graphical summaries LCOV and text/XML summaries gcovr