很多人看到這個標題時蹬挤,都會想“你都100%代碼覆蓋了缚窿,怎么還會有問題呢?”
讓我們看一下代碼例子:
public class TestCalculator {
public Double add(Double a, Double b) {
return a + b;}
}
再看看用junit寫出的測試代碼:
@Test
public void testAdd() {
Double a = new Double(1);
Double b = new Double(2);
Double c = new Double(3);
assertEquals(c, testCalculator.add(a, b));
}
當我們使用EclEmma或者Jacoco來進行覆蓋測試時焰扳,對于這個類倦零,我們將得到100%測試覆蓋率。
一切看起來都那么的完美吨悍,真是這樣的嗎扫茅?
好吧,讓我們來來看看另一個測試育瓜,當其中一個變量為null時葫隙,返回值將會是什么?
@Test
public void testAddNullPointerException() {
Double a = new Double(1);
Double b = null;
Double c = new Double(3);
assertEquals(c, testCalculator.add(a, b));
}
好了爆雹,你會發(fā)現(xiàn)盡管覆蓋率為100%停蕉,但程序卻拋出了NullPointerException。
那么肯定有人會問钙态,這樣的話單元測試覆蓋率的高低都不能作為衡量項目代碼質(zhì)量的指標慧起,那么我們要單元測試還有什么用?
首先册倒,我想我們可能搞錯了測試覆蓋的定義蚓挤。
我們先聽聽Martin Fowler對于測試覆蓋的定義:
Test coverage is a useful tool for finding untested parts of a codebase. Test coverage is of little use as a numeric statement of how good your tests are.
(圖片來自:https://martinfowler.com/bliki/TestCoverage.html)
他認為:把測試覆蓋作為質(zhì)量目標沒有任何意義,我們應(yīng)該把它作為一種發(fā)現(xiàn)未被測試覆蓋的代碼的手段驻子。
所以100%的代碼覆蓋率還值得追求嗎?
當然灿意,這應(yīng)該是每個程序員畢生的追求之一,但是如果從項目角度考慮ROI(投入產(chǎn)出比)崇呵,對于需要快速上線的短期項目缤剧,需要注重的是讓測試覆蓋核心功能代碼。如果你的項目是一個長期項目域慷,那么高覆蓋率是非常有必要的荒辕,它意味著高可維護性,以及更少的bug犹褒。(前提是你的測試采用TDD/BDD方式編寫抵窒,我見過將測試代碼寫的一團糟的人,看著他的代碼叠骑,我寧愿重新寫一遍)
那么對于一個項目來說李皇,覆蓋率應(yīng)該達到多少?
其實沒有適用于所有項目的數(shù)值宙枷,每個項目都應(yīng)有自己的閾值掉房,但共性是,測試必須覆蓋主要業(yè)務(wù)場景慰丛,代碼的邏輯分支也必須盡可能的覆蓋圃阳。
如何改進你的項目代碼覆蓋率?
首先我們要閱讀和理解項目代碼璧帝,找出其中需要測試并且與業(yè)務(wù)強相關(guān)的代碼捍岳,結(jié)合sonar等代碼質(zhì)量管理平臺,從代碼編寫規(guī)范睬隶、復(fù)雜度锣夹、重復(fù)代碼等方面進行代碼重構(gòu),進一步提高項目的可維護性與可讀性苏潜。
這也意味著重構(gòu)银萍,重構(gòu)的同時,你需要更多的測試來保證你重構(gòu)代碼的正確性恤左。
其次要對code coverage進行度量分析贴唇,那么我們應(yīng)該怎么度量code coverage搀绣?
一般來說我們從以下四個維度來度量,如上圖所示:
- 行覆蓋率(line coverage):度量被測代碼中每個可執(zhí)行語句是否都被執(zhí)行到戳气,但不包括java import链患,空行,注釋等瓶您。
- 函數(shù)覆蓋率(function coverage):度量被測代碼中每個定義的函數(shù)是否都被調(diào)用麻捻。
- 分支覆蓋率(branch coverage):度量被測代碼中每一個判定的分支是否都被測試到。
- 語句覆蓋率(statement coverage):度量被測代碼是否每個語句都被執(zhí)行呀袱。
所以行覆蓋率的高低不能說明項目的好壞贸毕,我們要從多方面進行思考,一般我們遵循的標準應(yīng)是:**函數(shù)覆蓋率 > 分支覆蓋率 > 語句覆蓋率****夜赵。
代碼覆蓋率最重要的意義在于:
閱讀分析之前項目中未覆蓋部分的代碼明棍,進而反推在前期QA以及相關(guān)測試人員在進行黑盒測試設(shè)計時是否考慮充分,沒有覆蓋到的代碼是否是測試設(shè)計的盲點寇僧,為什么沒有考慮到击蹲?是需求或者UX設(shè)計不夠清晰,還是測試設(shè)計的理解有誤婉宰。
檢測出程序中的廢代碼歌豺,可以逆向反推代碼設(shè)計中不合理的地方,提醒設(shè)計/開發(fā)人員理清代碼邏輯關(guān)系心包,提升代碼質(zhì)量类咧。
代碼覆蓋率高不能說明代碼質(zhì)量高,但是反過來看蟹腾,代碼覆蓋率低痕惋,代碼質(zhì)量絕對不會高到哪里去,可以作為測試自我審視的重要工具之一娃殖。
結(jié)束語
單元測試的覆蓋率并不只是為了取悅客戶或者管理層的數(shù)據(jù)值戳,它能夠?qū)崒嵲谠诜磻?yīng)項目中代碼的健康程度,幫助我們更好的改善了代碼的質(zhì)量炉爆,增加了我們對所編寫代碼的信心堕虹。