單元測試與覆蓋率

文中圖片來源互聯(lián)網(wǎng)

“Unit testing is often talked about in software development, and is a term that I've been familiar with during my whole time writing programs. Like most software development terminology, however, it's very ill-defined, and I see confusion can often occur when people think that it's more tightly defined than it actually is. — Martin Fowler”

因何而生

正如Martin Fowler說的歇拆,單元測試這個詞在軟件開發(fā)中高頻次地出現(xiàn),它聚焦于系統(tǒng)的某一部分,通常是較低級別印蔬,比如類、方法等,是一種以較小代價換取軟件“正確”的方法蹭睡。這里提到了一個很重要的概念,即怎么樣理解軟件“正確”赶么?

在我看來軟件的正確性包含以下幾個點(diǎn):

  • 流程符合預(yù)期肩豁,即按照設(shè)計的步驟運(yùn)行,并在關(guān)鍵的步驟執(zhí)行正確的功能辫呻,包含正確的參數(shù)清钥;
  • 執(zhí)行效果符合預(yù)期,即通過功能執(zhí)行后放闺,能夠產(chǎn)生符合設(shè)計的結(jié)果祟昭,這種結(jié)果可以是直接的,比如方法的返回值怖侦;也可以是間接的篡悟,比如方法改變了實(shí)例中可被觀察到的部分;
  • 異常保護(hù)符合預(yù)期匾寝,功能執(zhí)行過程會遭遇超越設(shè)計邊界的場景搬葬,保護(hù)自身不因“越界”而失效;
  • 質(zhì)量屬性符合預(yù)期艳悔,某些功能具有質(zhì)量屬性急凰,如響應(yīng)時間等。

單元測試應(yīng)圍繞上述理解展開猜年,它需要且應(yīng)當(dāng)說明被測功能的正確香府,比如下面這些我們常見的單元測試寫法。

public class AppTest {
    // 驗(yàn)證流程符合預(yù)期的測試
    @Test
    public void should_give_tips_when_input_length_not_4() throws Exception {
        // given

        // when
        when(interactable.read()).thenReturn("231").thenReturn("1234");
        app.play();
        // then
        verify(interactable).write("Please input 4 none repeatable numbers(You have 6 times).");
    }

    // 驗(yàn)證執(zhí)行效果符合預(yù)期的測試
    @Test
    public void should_out_buzz_when_number_is_multiples_of_five() throws Exception {
        // given

        // when
        final String result = rule.transform(5);
        // then
        assertThat(result, is("Buzz"));
    }

    // 驗(yàn)證異常保護(hù)符合預(yù)期的測試
    @Test(expected = Exception.class)
    public should_throw_exception_when_input_invalid() throws Exception {
        // given

        // when

        // then
    }
}

覆蓋率或測試覆蓋率是用來衡量單元測試對功能代碼的測試情況码倦,通過統(tǒng)計單元測試中對功能代碼中行、分支锭碳、類等模擬場景數(shù)量袁稽,來量化說明測試的充分度。覆蓋率的前提是存在單元測試擒抛,并且從其本意上推導(dǎo)推汽,可被統(tǒng)計覆蓋率的單元測試應(yīng)當(dāng)是證明了軟件正確的补疑,這是一個不能動搖的基礎(chǔ),否則一切就失去意義歹撒。

覆蓋率報告

從上述分析不難看出單元測試與覆蓋率的側(cè)重點(diǎn)是不一樣的莲组,單元測試重點(diǎn)在于驗(yàn)證軟件正確,而覆蓋率重點(diǎn)在于描述測試的充分程度暖夭,兩者不會等同起來锹杈,但在項(xiàng)目和團(tuán)隊(duì)中一個普遍的認(rèn)識是“高覆蓋率的代碼,其功能的正確性是得到保障的”迈着。

誤入歧途

覆蓋率在持續(xù)集成中一般會作為代碼準(zhǔn)入的標(biāo)準(zhǔn)竭望,這種選擇來源于原則“沒有測試覆蓋的代碼是不可靠的”以及它的變化衍生。大多數(shù)項(xiàng)目都會設(shè)定一個覆蓋率的門限值裕菠,禁止無測試的代碼合入同時還要警告覆蓋率的降低咬清。通常來說這么做是合理的,持續(xù)集成中覆蓋率檢查以一種顯性的約束來規(guī)范開發(fā)人員使用單元測試保障開發(fā)代碼的正確性奴潘,并讓單元測試逐漸地變成開發(fā)習(xí)慣旧烧。不得不說,覆蓋率檢查對單元測試的普及起了十分積極的作用画髓。

但最近的一些發(fā)現(xiàn)讓我對覆蓋率的認(rèn)識產(chǎn)生了一些擔(dān)憂掘剪,在走查代碼的過程中發(fā)現(xiàn)了一些寫法十分奇特的單元測試,類似下面代碼:

public class GameTest {
    @Test
    public void testVerify() throws Exception {
        // given

        // when
        new Game("1234").verify("1234");
        // then
        
    }
}

這樣的代碼乍看是沒有什么問題的雀扶,使用了測試框架杖小,調(diào)用了被測對象的外部接口,覆蓋率報告上也有體現(xiàn)愚墓,一句話——完美予权!

完美

但細(xì)探一下就發(fā)現(xiàn)如此完美的測試代碼偏偏少了最重要的東西——對預(yù)期的判斷,就是我們上面提到的軟件正確性的4點(diǎn)浪册。這就太糟糕了扫腺,因?yàn)槌善臏y試根本沒有辦法告訴開發(fā)人員他們寫的代碼究竟是否正確,既然沒有了對錯那么單元測試的意義又何在呢村象?

不忍直視

為何會出現(xiàn)上面的測試呢笆环?在與開發(fā)人員交流后發(fā)現(xiàn)覆蓋率在這其中起了很大的因素。當(dāng)項(xiàng)目劃定了代碼準(zhǔn)入的覆蓋率門限后厚者,在短時間內(nèi)大量的代碼是無法提交入庫的躁劣,而項(xiàng)目又對功能發(fā)布有較強(qiáng)的deadline,在這兩種因素的共同作用下库菲,就會有人想到上述的“奇招”账忘,這樣的測試不會檢驗(yàn)功能的正確,而會產(chǎn)生符合要求的高覆蓋率。更糟糕的是鳖擒,由于無法驗(yàn)證功能的正確即無法產(chǎn)生價值于開發(fā)人員溉浙,那么測試這件事就會受到抵制,同時測試代碼也會耗散有限的迭代時間蒋荚,造成對單元測試的認(rèn)同更加低落戳稽,使得一些本可以逐漸落地的方法,如測試驅(qū)動開發(fā)期升,變成空中樓閣惊奇。

正本清源

現(xiàn)在再回頭看我們之前提到的關(guān)于單元測試和覆蓋率的普遍認(rèn)識:“高覆蓋率的代碼,其功能的正確性是得到保障的”吓妆,你還認(rèn)為這句話一定正確嗎赊时?

單元測試的目的是為了以較小的代價(白盒)換取軟件正確,而覆蓋率的目的是在有效單元測試的基礎(chǔ)上統(tǒng)計測試代碼測試被測對象的充分程度行拢。兩者存在聯(lián)系卻不能相互替換祖秒。誠然,在保證單元測試實(shí)現(xiàn)其目的的情況下舟奠,上述認(rèn)識才真正變得有意義竭缝,如果混淆了單元測試和覆蓋率的意義,那么就會出現(xiàn)上面的舍本逐末沼瘫,此時寫再多的測試也不能證明軟件的正確抬纸,只能證明你對單元測試和覆蓋率的誤解有多深!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末耿戚,一起剝皮案震驚了整個濱河市湿故,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌膜蛔,老刑警劉巖坛猪,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異皂股,居然都是意外死亡墅茉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進(jìn)店門呜呐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來就斤,“玉大人,你說我怎么就攤上這事蘑辑⊙蠡” “怎么了?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵洋魂,是天一觀的道長绷旗。 經(jīng)常有香客問我啄踊,道長,這世上最難降的妖魔是什么刁标? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮址晕,結(jié)果婚禮上膀懈,老公的妹妹穿的比我還像新娘。我一直安慰自己谨垃,他們只是感情好启搂,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著刘陶,像睡著了一般胳赌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上匙隔,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天疑苫,我揣著相機(jī)與錄音,去河邊找鬼纷责。 笑死捍掺,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的再膳。 我是一名探鬼主播挺勿,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼喂柒!你這毒婦竟也來了不瓶?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤灾杰,失蹤者是張志新(化名)和其女友劉穎蚊丐,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吭露,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吠撮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了讲竿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泥兰。...
    茶點(diǎn)故事閱讀 40,872評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖题禀,靈堂內(nèi)的尸體忽然破棺而出鞋诗,到底是詐尸還是另有隱情,我是刑警寧澤迈嘹,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布削彬,位于F島的核電站全庸,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏融痛。R本人自食惡果不足惜壶笼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望雁刷。 院中可真熱鬧覆劈,春花似錦、人聲如沸沛励。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽目派。三九已至坤候,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間企蹭,已是汗流浹背白筹。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留练对,地道東北人遍蟋。 一個月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像螟凭,于是被迫代替她去往敵國和親虚青。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 文章來自:http://blog.csdn.net/mj813/article/details/52451355 ...
    好大一只鵬閱讀 9,193評論 2 126
  • 1.測試與軟件模型 軟件開發(fā)生命周期模型指的是軟件開發(fā)全過程螺男、活動和任務(wù)的結(jié)構(gòu)性框架棒厘。軟件項(xiàng)目的開發(fā)包括:需求、設(shè)...
    Mr希靈閱讀 21,965評論 7 278
  • 1.測試與軟件模型 軟件開發(fā)生命周期模型指的是軟件開發(fā)全過程下隧、活動和任務(wù)的結(jié)構(gòu)性框架奢人。軟件項(xiàng)目的開發(fā)包括:需求、設(shè)...
    宇文臭臭閱讀 6,729評論 5 100
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,332評論 25 707
  • 移動互聯(lián)網(wǎng)就是手機(jī)上網(wǎng)的意思淆院。手機(jī)是可以移動的何乎,手機(jī)也能上網(wǎng)了,所以叫移動互聯(lián)網(wǎng)土辩。移動互聯(lián)網(wǎng)是互聯(lián)網(wǎng)和移動的結(jié)合支救。...
    人生如夢z閱讀 697評論 0 1