什么是單元測試覆蓋率 蚁鳖?
單元測試覆蓋率是一種軟件測試的度量指標(biāo)醉箕,指在所有功能代碼中,完成了單元測試的代碼所占的比例放棒。有很多自動化測試框架工具可以提供這一統(tǒng)計數(shù)據(jù)间螟,其中最基礎(chǔ)的計算方式為:
單元測試覆蓋率 = 被測代碼行數(shù) / 參測代碼總行數(shù) * 100%
Note: 一般情況下厢破, 參測代碼總行數(shù)是指排除配置文件治拿、以及測試代碼本身的所有功能代碼的總行數(shù)劫谅。
單元測試的度量方式
最常見的單元測試覆蓋率的度量方式有以下三種:
1. 行覆蓋率 / 語句覆蓋
這種覆蓋率統(tǒng)計方式是最為基礎(chǔ)的同波,它可以用于體現(xiàn)參測代碼中已被執(zhí)行和未被執(zhí)行的代碼行(語句)未檩,從而可以進(jìn)一步推斷代碼的邏輯覆蓋是否全面。
2. 分支覆蓋
這種覆蓋率統(tǒng)計方式是用于統(tǒng)計代碼中所有判斷分支是否都被覆蓋冤狡,如
...
if (condition)
{
Operation_1();
}
else
{
Operation_2();
}
...
語句就會根據(jù) condition
的值產(chǎn)生兩個不同的分支操作悲雳,那么在統(tǒng)計分支覆蓋時,就需要對兩個分支都進(jìn)行校驗坦胶。值得注意的是顿苇,上例中的代碼税弃,其分支覆蓋可以被行覆蓋所取代,也就是說若上面代碼的行覆蓋率為100%幔翰, 則其分支覆蓋率亦為100%遗增。
但是如果將代碼換為三元表達(dá)式款青,如
...
condition ? Operation_1() : Operation_2();
...
此時可都,行覆蓋率在統(tǒng)計時渠牲,只要這一行代碼有被執(zhí)行,那么行覆蓋率必然為100%瘫镇,并不關(guān)心是否兩種情況都被執(zhí)行過铣除。但如此一來就沒辦法通過行覆蓋率保證其分支覆蓋率為100% 了尚粘。
3.條件覆蓋
這種覆蓋統(tǒng)計方式是針對代碼中產(chǎn)生多分支郎嫁,并且每個分支的激活條件比較復(fù)雜的情況泽铛。
代碼的分支一般都是通過流程控制語句產(chǎn)生的,而流程控制語句再激活一個分支時是需要條件的杠茬,依然以之前的代碼為例澈蝙,若condition
是幾個布爾值的組合灯荧,
...
if (Condition())
{
Operation_1();
}
else
{
Operation_2();
}
...
private bool Condition () {
return condition_1 || condition_2 && condition_3;
}
那么此時逗载,代碼依然只有兩個分支厉斟,但是由于激活條件是取決于condition_1, condition_2, condition_3
的組合情況强衡,那么在校驗條件覆蓋時感挥,就應(yīng)該考慮所有可能的組合情況,也就是8種測試用例触幼。這樣才可以使條件覆蓋的覆蓋率達(dá)到100%置谦。全面考慮條件覆蓋的做法就可以達(dá)到優(yōu)化測試的效果媒峡。
其實谅阿,覆蓋率的統(tǒng)計方式還是用很多其他種類的奔穿,這里給出的只是幾種最基礎(chǔ)的贱田。但不管怎樣男摧,完備的單元測試行覆蓋都是其他度量方式的基礎(chǔ)耗拓。當(dāng)行覆蓋率達(dá)標(biāo)之后,開發(fā)人員才會有精力修改奏司、優(yōu)化測試用例乔询,從而提高分支覆蓋率、條件覆蓋率等其他更具業(yè)務(wù)價值的單元測試覆蓋率韵洋。
提高單元測試覆蓋率的意義與價值
有些時候竿刁,我們想提高項目測試覆蓋率的閾值,比如從45% 提高到80%搪缨,又或者從 95% 提高到100%食拜。
那么這個時候,我們就需要問一問自己副编,為什么要做這樣的事情负甸?提高覆蓋率的意義與價值何在?
1. 是想通過單元測試來保證代碼質(zhì)量痹届?
單元測試的覆蓋率高與代碼質(zhì)量高队腐,二者并沒有直接關(guān)系,這是因為覆蓋率的高低完全是可以“造假”的。一些沒有實際業(yè)務(wù)價值的測試用例因運而生荸型,甚至發(fā)生類似 AssertionFreeTesting 的情況辕狰,使覆蓋率“虛高”。
因此,我們沒有依據(jù)說明高覆蓋率就能確保好的代碼質(zhì)量母剥。
2. 是想通過單元測試保證業(yè)務(wù)邏輯不會出錯秦爆?
用單元測試保證業(yè)務(wù)邏輯芬膝,看上去很有道理。可是仔細(xì)一想,就會發(fā)現(xiàn)這一點,其實有些不切實際罩句。一個業(yè)務(wù)功能的實現(xiàn)并不僅僅依賴于某一個方法诅福、某一個類赂乐,那么通過單元測試能夠保證的業(yè)務(wù)邏輯也是十分有限的浅役,不可能做到“不會出錯”瞪讼。
可以試想希柿,如果僅僅依靠測試金字塔最底層的單元測試盾戴,使其覆蓋率達(dá)標(biāo)就能保證業(yè)務(wù)邏輯不出錯,那么為什么還需要更高層的集成測試和功能測試,甚至探索性測試呢?
另一方面,如果是想將單元測試與業(yè)務(wù)邏輯相綁定遥金,那么方向也不應(yīng)是提高覆蓋率美莫,而應(yīng)該是提供更加符合業(yè)務(wù)場景的測試用例給已有的單元測試,也就是提高已有的單元測試質(zhì)量科阎。
如此一來述吸,這兩個問題都無法通過提高單元測試覆蓋率解決,那么我們提高覆蓋率還有什么意義與價值呢茅逮?
測試覆蓋率幫助我們找到?jīng)]有被測試的代碼挺身。
提高測試覆蓋率惨撇,可以讓我們在重構(gòu)帆卓、優(yōu)化這些沒有被測試的代碼時更有底氣剑令。
但是,最大的前提是你的測試代碼是值得信任的拄查。
那么現(xiàn)在吁津,我們可以考慮一下這兩種情況了:
- 將覆蓋率從 45% 提高到 80%。
- 將覆蓋率從 95% 提高到100%堕扶。
對于第一種情況碍脏,不到一般的初始測試覆蓋率而言,首先會讓開發(fā)人員在進(jìn)行重構(gòu)時很沒有安全感稍算,由于未被測試覆蓋的代碼量太多典尾,從而無法快速發(fā)現(xiàn)改動是否會對未覆蓋的代碼帶來不良影響。 因此糊探,在這種情況下钾埂,提高代碼的覆蓋率河闰,從而讓更多的代碼被測試,讓開發(fā)者在重構(gòu)時能更放心褥紫,這對項目更有益淤击。
而對于第二種情況,可以看到覆蓋率已經(jīng)很高了故源,那么這個時候污抬,
首先看看開發(fā)者經(jīng)常改動或重構(gòu)的代碼是否都被覆蓋,如果是绳军,則重點應(yīng)該放在優(yōu)化測試用例上印机,看看是否所有的邊界條件都被測試,所有的分支都被覆蓋等等门驾。因為這時射赛,提高已有的單元測試質(zhì)量,讓測試用例更貼近業(yè)務(wù)場景所帶來的收益會遠(yuǎn)遠(yuǎn)大于進(jìn)一步提高測試覆蓋率所帶來的收益奶是。
否則楣责,一旦重構(gòu)了未被覆蓋的參測代碼,就應(yīng)該為改代碼添加單元測試聂沙,使之被覆蓋秆麸,從而確保功能的正常運作。
總結(jié)
- 單元測試僅用來保證代碼所對應(yīng)的功能正常及汉,若想將之與業(yè)務(wù)結(jié)合沮趣,需要貼合業(yè)務(wù)場景的測試用例。
- 單元測試覆蓋率僅用來找出未被測試的代碼坷随,若想通過覆蓋率保證業(yè)務(wù)邏輯房铭,需要進(jìn)一步優(yōu)化已有單元測試的質(zhì)量。
- 提高單元測試覆蓋率僅對之前沒有測試覆蓋或覆蓋極其不足的代碼有顯著增益温眉,若想對已經(jīng)被測試高度覆蓋的代碼進(jìn)行優(yōu)化缸匪,需要著眼于提升已有的測試用例質(zhì)量。
- 團(tuán)隊合作開發(fā)类溢,應(yīng)盡量保證自己每次提交的代碼都已經(jīng)全部被測試覆蓋凌蔬。