硬核:嵌入式代碼覆蓋率統(tǒng)計(jì)方法和經(jīng)驗(yàn)
代碼覆蓋率是衡量軟件測(cè)試完成情況的指標(biāo),通?;跍y(cè)試過(guò)程中已檢查的程序源代碼比例計(jì)算得出。代碼覆蓋率可以有效避免包含未測(cè)試代碼的程序被發(fā)布。
1. 問(wèn)題背景
2. 解決方法
2.1 覆蓋率工具
2.3 實(shí)踐應(yīng)用
ifeq (_CODE_COV,$(CODE))
APP_FLAGS += -fprofile-arcs -ftest-coverage
endif
ifeq (_CODE_COV,$(CODE))
LD_LINK_LIBFILTER += -fprofile-arcs -ftest-coverage
endif
圖2 LCOV生成HTML結(jié)果
3.?高手總結(jié)方法
代碼覆蓋率等級(jí)
代碼覆蓋率可以通過(guò)多種方法測(cè)量。最常用的是測(cè)量以下一個(gè)或多個(gè)指標(biāo):語(yǔ)句覆蓋率,分支 覆蓋率,修訂的條件/判定覆蓋率(MC/DC)。以下章節(jié)中將逐一詳解這些代碼覆蓋率。
語(yǔ)句覆蓋率
語(yǔ)句覆蓋率用來(lái)度量被測(cè)代碼中的可執(zhí)行語(yǔ)句是否被執(zhí)行到,它并不考慮循環(huán)或者條件語(yǔ)句, 只針對(duì)語(yǔ)句度量可執(zhí)行代碼。應(yīng)當(dāng)特別注意的是:“語(yǔ)句”并不等同于代碼行。
一般情況下,對(duì)于 C,C++,Java或Ada,分號(hào)代表語(yǔ)句結(jié)束。在某些情況下,一條語(yǔ)句會(huì)跨越多行代碼。語(yǔ)句覆蓋率可以有效度量可執(zhí)行代碼是否被執(zhí)行,但同時(shí)也有一定的局限性。
語(yǔ)句覆蓋率的局限
考慮如下圖1的代碼段:
int* p = NULL;
if (condition)
p = &variable;
*p = 123;
圖 1 – 語(yǔ)句覆蓋局限代碼示例
如果“condition”為true,那么就有可能達(dá)到100%的語(yǔ)句覆蓋,然而這個(gè)測(cè)試用例忽略了另一種情況:如果“condition”為假,程序?qū)⒁每罩羔?,因此,雖然語(yǔ)句覆蓋率是一個(gè)很好的度量指標(biāo),它仍舊是入門級(jí)的代碼覆蓋率。理想情況下,即使“condition”為false,測(cè)試用例也應(yīng)當(dāng)被計(jì)算。
分支覆蓋率
分支覆蓋率用來(lái)度量程序中所有的判定和分支以及相應(yīng)的輸出是否都被測(cè)試執(zhí)行到,例如 “if”語(yǔ)句必須將“true”和“false”都考慮到以覆蓋所有的輸出。如果只有一個(gè)路徑被執(zhí)行,那么覆蓋率將被標(biāo)記為部分執(zhí)行。
和語(yǔ)句覆蓋率類似,分支覆蓋浪費(fèi)也有一些需要注意的細(xì)節(jié),尤其在針對(duì)“惰性求值”的編程語(yǔ)言時(shí),惰性求值是將代碼的求值操作延遲到需要結(jié)果值時(shí)再進(jìn)行的一項(xiàng)技術(shù)。
分支覆蓋率的局限
典型的情況是當(dāng)有復(fù)雜的布爾表達(dá)式的“惰性求值”出現(xiàn)時(shí),如下圖2的代碼片段:
int* p = NULL;
if (condition1 && (condition2 || function1(*p)))
statement1;
else
考慮“condition1”為假的情況,惰性求值將不會(huì)度量“condition2”或,此種情況同樣會(huì)導(dǎo)致代碼“if (condition1 && (condition2 || function1(*p)))”的分支覆蓋率計(jì)算錯(cuò)誤。
繼續(xù)考慮“condition1”和“condition2”都為真的情況。惰性求值將再次導(dǎo)致“function1(*p)” 不會(huì)被度量,也同樣會(huì)導(dǎo)致代碼“if (condition1 && (condition2 || function1(*p)))”的分支覆蓋率計(jì)算錯(cuò)誤。在此種情況下,有可能出現(xiàn)分支覆蓋率為100%但軟件中仍有潛在缺陷的情況。
修訂條件/判定覆蓋率(MC/DC)
MC/DC是一種特殊的分支覆蓋率,它不但會(huì)使用分支覆蓋率報(bào)告復(fù)雜條件下的true和false輸出,同時(shí)也會(huì)報(bào)告復(fù)雜條件下的全部分支條件輸出。
MC/DC最初由波音公司創(chuàng)建,用于航空軟件中DO-178B的A級(jí)認(rèn)證。通過(guò)對(duì)所有的子條件輸出分支的獨(dú)立證明,有效解決了惰性求值帶來(lái)的問(wèn)題。
繼續(xù)討論代碼示例2,我們需要在“condition2”和“function1(*p)”固定的條件下驗(yàn)證“condition1” 的“true”和“false”判定分支,之后繼續(xù)固定“condition1”和“function1(*p)”驗(yàn)證“condition2” 的判定分支。
同樣的,讓我們?cè)诠潭ā癱ondition1”和“condition2”的條件下討論 “function1(*p)”。在其他分支條件固定的情況下驗(yàn)證某個(gè)分支條件的“true”和“false”值稱作“MC/DC對(duì)”。MC/DC對(duì)一般 使用MC/DC真值表描述。表1就是一個(gè)MC/DC真值表示例。
在軟件開(kāi)發(fā)的不同階段獲取覆蓋率
軟件測(cè)試有很多種類,本文將其簡(jiǎn)要的分為三類:
> 系統(tǒng)/函數(shù)測(cè)試:測(cè)試集成后的整個(gè)應(yīng)用
> 集成測(cè)試:測(cè)試集成的子系統(tǒng)
> 單元測(cè)試:測(cè)試一個(gè)或多個(gè)文件或類
每個(gè)軟件項(xiàng)目在系統(tǒng)測(cè)試的過(guò)程中都會(huì)模擬最終用戶的操作對(duì)源代碼做一些系統(tǒng)測(cè)試。導(dǎo)致軟件發(fā)布后仍舊存在缺陷最重要的一個(gè)原因通常是程序在運(yùn)行過(guò)程中遇到了非預(yù)期的,即沒(méi)有測(cè)試的輸入組合。
很多軟件項(xiàng)目并不是沒(méi)有做集成測(cè)試或者單元測(cè)試。只是在完成集成測(cè)試或單元測(cè)試后,開(kāi)發(fā)團(tuán)隊(duì)可能苦于為隔離程序中的單個(gè)或多個(gè)文必須所需的大量測(cè)試代碼量。
對(duì)于最嚴(yán)格的單元測(cè)試和集成測(cè)試來(lái)說(shuō),最終生成的測(cè)試代碼量比待測(cè)代碼量還要龐大是很經(jīng)常出現(xiàn)的情況。因此,這兩種級(jí)別的測(cè)試普遍適用于關(guān)鍵和高安全領(lǐng)域,例如:航空航天、醫(yī)療、交通運(yùn)輸、工業(yè)過(guò)程控制、高速汽車等。此類軟件中包含大量的嵌入式應(yīng)用軟件。
關(guān)鍵領(lǐng)域的結(jié)構(gòu)化測(cè)試流程一般會(huì)將需求的級(jí)別高低作為重點(diǎn),代碼覆蓋率因而會(huì)在這種“基于需求”的測(cè)試中進(jìn)行分析。在許多項(xiàng)目中,高等級(jí)的需求最先被測(cè)試。此時(shí)代碼覆蓋率可以被用來(lái)檢測(cè)和報(bào)告所達(dá)到的覆蓋比例。
然而不幸的是,在系統(tǒng)測(cè)試和功能測(cè)試階段想要達(dá)到100%的代碼覆蓋率幾乎是不可能的。通常情況下系統(tǒng)測(cè)試和功能測(cè)試只能達(dá)到60%-70%的代碼覆蓋率,剩余30%-40%的代碼覆蓋率需要在單元測(cè)試和集成測(cè)試階段才能夠完成。
單元測(cè)試使用包含驅(qū)動(dòng)和樁的測(cè)試代碼隔離系統(tǒng)中的特定函數(shù),同時(shí)使用測(cè)試用例模擬這些函數(shù)的執(zhí)行。這些所謂的“低等級(jí)測(cè)試需求” 對(duì)被測(cè)試代碼提供了更高的控制,可以提高先前執(zhí)行的系統(tǒng)測(cè)試覆蓋率(甚至能達(dá)到100%)。因此,在不同的測(cè)試之間共享覆蓋率數(shù)據(jù)是非常有必要的。
嵌入式環(huán)境中獲取覆蓋率帶來(lái)的挑戰(zhàn)
常言道“有得必有失”,在嵌入式環(huán)境獲取代碼覆蓋率的問(wèn)題上,要付出的代價(jià)是對(duì)待測(cè)代碼額外的插樁工作。插樁是將額外的代碼添加到程序中,從而實(shí)現(xiàn)測(cè)試過(guò)程中的覆蓋率收集和分析操作。
由于插樁的相關(guān)操作將導(dǎo)致程序源代碼增多,進(jìn)而延長(zhǎng)程序的執(zhí)行時(shí)間,因而需要預(yù)測(cè)插樁后的源代碼的覆蓋范圍預(yù)測(cè),尤其當(dāng)測(cè)試實(shí)時(shí)嵌入式系統(tǒng)環(huán)境時(shí),此項(xiàng)工作就更為重要。
事實(shí)上,要精準(zhǔn)的預(yù)測(cè)程序文件插樁的影響幾乎是不可能的。沒(méi)有算法支持(也不可能有)。每個(gè)系統(tǒng)都包含很多的變量,具有獨(dú)立唯一的復(fù)雜性。當(dāng)然,對(duì)于典型的示例系統(tǒng)來(lái)說(shuō),獲取一組準(zhǔn)確的估計(jì)還是可能實(shí)現(xiàn)的。
在共享環(huán)境中獲取覆蓋率數(shù)據(jù)
在嵌入式環(huán)境下管理代碼覆蓋率的主要問(wèn)題在于如何配置內(nèi)存以容納額外的插樁代碼。VectorCAST針對(duì)大量示例代碼評(píng)估后發(fā)現(xiàn)添加了上文中提出的各種覆蓋率額外配置之后,源代碼量增長(zhǎng)量普遍達(dá)到了10%。對(duì)于絕大多數(shù)的32位目標(biāo)板,這并不是一個(gè)很大的問(wèn)題,但對(duì)于存儲(chǔ)容量有限的8位或者16位目標(biāo)板來(lái)說(shuō),幾乎可以肯定這會(huì)是一個(gè)問(wèn)題。
為了降低可執(zhí)行文件的大小,各種各樣的代碼插樁技術(shù)被發(fā)明出來(lái),針對(duì)不同大小的存儲(chǔ)區(qū)域有不同的數(shù)據(jù)采集技術(shù)。植入存儲(chǔ)器內(nèi)部的收集系統(tǒng)可以用于監(jiān)測(cè)被檢測(cè)到的代碼。這是插樁技術(shù)中保證使用最少RAM的關(guān)鍵技術(shù)。
4. 結(jié)語(yǔ)
代碼覆蓋率能不能提高軟件的可靠性?答案是肯定的,代碼的覆蓋率分析是保證軟件質(zhì)量最簡(jiǎn)便易行的方法。
成功為華為“續(xù)命:中國(guó)芯片之父張汝京
這位“華為天才少年”,竟然要我用“充電寶”打《只狼》
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!