簡介
代碼覆蓋是由系統化軟體測試所衍生的方式。第一份出版的相關參考資料是Miller及Maloney1963年在ACM通訊上發表的論文。
代碼覆蓋是飛行設備進行安全認證中的考量項目之一。飛行設備相關認證的指南列在
美國聯邦航空管理局的檔案DO-178B及最近出版的檔案DO-178C。
功能安全標準,如IEC 61508或ISO 26262,並未定義程式碼覆蓋率之需求值,只列為軟體測試方法的選項,唯有航太產業標準(DO-178B)要求100%,以因應超高可靠度的產品需求,此數值對於工業或汽車產品實屬理想目標。
覆蓋率準則
為了量測
測試套件測試軟體的程度,會用一種或多種不同的覆蓋率準則。
基本的覆蓋率準則
以下列出一些基本的覆蓋率準則:
函式覆蓋率(Function coverage):有呼叫到程式中的每一個函式(或副程式)嗎?
指令覆蓋率(Statement coverage):若用
控制流圖表示程式,有執行到控制流圖中的每一個節點嗎?
判斷覆蓋率(Decision coverage):(和分支覆蓋率不同)若用控制流圖表示程式,有執行到控制流圖中的每一個邊嗎?例如控制結構中所有IF指令都有執行到邏輯運算式成立及不成立的情形嗎?
條件覆蓋率(Condition coverage):也稱為謂詞覆蓋(predicate coverage),每一個邏輯運算式中的每一個條件(無法再分解的邏輯運算式)是否都有執行到成立及不成立的情形嗎?條件覆蓋率成立不表示判斷覆蓋率一定成立。
條件/判斷覆蓋率(Condition/decision coverage):需同時滿足判斷覆蓋率和條件覆蓋率。
考慮以下的C++函式:
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%的條件。
考慮以下的程式:
if a and b then
以下二個測試可以得到100%的條件覆蓋率:
a=true,b=false
a=false,b=true
但上述的測試條件都不會使if的邏輯運算式成立,因此不符合判斷覆蓋的條件。
有時會需要用錯誤插入的方式來確保所有條件及
異常處理程式都有一定的覆蓋率。
修改條件/判斷覆蓋
在一些安全關鍵套用(例如飛航用的軟體)中,一般會需要滿足修改條件/判斷覆蓋(modified condition/decision coverage,簡稱MC/DC)的準則。此準則是條件/判斷覆蓋的延伸,而且每個條件都要可以獨立影響判斷結果的成立或不成立。例如考慮以下的程式:
if (a or b) and c then
以下的測試可滿足條件/判斷覆蓋:
不過,若第一項測試中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個測試:
其他覆蓋率準則
以下也是一些可能會用到的覆蓋率準則:
JCSAJ覆蓋率:是否執行過每一個JCSAJ(線性代碼序列和跳轉)?
JJ路徑覆蓋率(JJ-Path coverage):是否執行過每一個JJ路徑(從跳轉到跳轉之間的路徑,也就是JCSAJ)?
路徑覆蓋率(Path coverage):是否執行過程式中所有可能的路徑?
進入點/結束點覆蓋率(Entry/exit coverage):是否執行過函式中所有可能的進入點及結束點?
循環覆蓋率(Loop coverage):所有循環是否都有執行過零次、一次及一次以上的測試?
參數值覆蓋率(Parameter Value Coverage):對於一個方法的所有參數,是否有執行過其中最常見的數值?
安全關鍵套用一般會要求某種特定的覆蓋率要到達100%。
有些覆蓋之間有相關性:例如路徑覆蓋就包括了判斷覆蓋、指令覆蓋及進入點/結束點覆蓋,而判斷覆蓋也包括了指令覆蓋。
完整的路徑覆蓋測試多半難以實現甚至不可能實現。有
個判斷的程式就會有
種完整路徑,循環結構可能會產生無窮種完整路徑。程式中的許多路徑也許是不可行的,因為也許沒有受測系統的輸入,使系統完整依某特定路徑執行。而且已證實沒有識別不可行路徑的通用算法(若有,此算法就可以求解
停機問題)。實務上路徑覆蓋測試的軟體只會試圖找出隨著循環執行次數不同時,有變動的路徑,設法找到“基本路徑”,並要求對基本路徑需達到路徑覆蓋的要求。
實務
目標軟體是在特定環境下配合特定的選項或函式庫所建立,所執行的每一個函式都會對應到原代碼的機能點,代碼覆蓋的程式可以讓程式開發者及品質保證單位可以找出程式在正常情形下不會執行或是很少執行的部分(例如異常處理程式),也幫助測試工程師確認最重要的條件(機能點)是否有測試到。測試結果可進行分析,確認哪一部分程式尚未執行到,後續再修改測試程式,對這部分進行必要的測試。上述作法的目的是為了開發一套嚴格且可管理的
回歸測試。
在配合軟體開發環境進行代碼覆蓋率時,需考慮以下的事項:
測試工程師可以根據代碼覆蓋測試的報告來調整測試用例、輸入或是組態,以增加重要機能的代碼覆蓋率。測試工程師常常會使用到指令覆蓋及判斷覆蓋,前者會報告在測試中會執行到多少比例的程式碼,後者會報告在測試中會執行到多少比例的的判斷結果,二者都會輸出一個覆蓋率的度量,以百分比表示。其意義則需視進行的代碼覆蓋種類來決定,67%的判斷覆蓋率會比67%的指令覆蓋率會來得全面。
一般而言代碼覆蓋工具及函式庫會影響程式性能,也會消耗記憶體或其他資源,無法在系統正常使用時測試。因此一般只在開發階段進行,提供給客戶的系統不會包括代碼覆蓋工具及函式庫。也有一些軟體無法用覆蓋測試來測試,其覆蓋率會用分析的方式來得到近似值,而不是用直接測試到的結果。
有一些缺陷會受到代碼覆蓋工具的影響,像在進行代碼覆蓋測試時,可以略過一些有
競爭危害或是
實時敏感度高的程式。相對的,當加上額外的代碼覆蓋測試碼時,也可能比較容易找到這類的缺陷。