一枚程序員眼中的單元測(cè)試

論測(cè)試的重要性

如今程序員群體趕上了中國(guó)最龐大的農(nóng)民群體阶捆,大街上隨便抓一把,十有八九是程序員钦听,還一個(gè)剛從某國(guó)企離職報(bào)名參加軟件培訓(xùn)班洒试。我想碼農(nóng)的稱號(hào)或許就是這么來(lái)的吧。

在外行人看來(lái)朴上,程序員是一個(gè)成天對(duì)著電腦倒騰著代碼垒棋、看著Terminal上行云流水般的打印、過(guò)著不修邊幅的日子外加超負(fù)荷的碼農(nóng)痪宰。

在內(nèi)行人看來(lái)叼架,程序員是一個(gè)成天面對(duì)QA的"質(zhì)疑"、PM的"奪命催"以及DEVs的"吐槽"衣撬,扛著身心壓力的苦行僧乖订。

在我看來(lái),程序員應(yīng)該是:

手持神劍具练,心懷善念乍构,胸有成竹、有理有據(jù)并且合情合理地跟QA扛点、PM哥遮、DEV斗智斗勇的戰(zhàn)士。

要擺脫QA的質(zhì)疑陵究、DEVs的吐槽以及PM的奪命催眠饮,除了那些不容易掌控的客觀因素,我們可以從自身發(fā)力铜邮,加強(qiáng)自身的"核心肌群"君仆,呈現(xiàn)出自己的應(yīng)有的專業(yè)態(tài)度,編寫出高質(zhì)量的代碼牲距,從而促成高質(zhì)量的交付返咱。

如何交付高質(zhì)量的代碼?

首先牍鞠,我們可以擺出苦行僧的心態(tài)咖摹,平日里練就一身好把式:如Clean Code、Refactor难述、OOD及FOP萤晴。即便這樣吐句,牛逼哄哄的程序員也不敢說(shuō)自己的代碼百分之百?zèng)]有缺陷。

怎么辦店读,兩個(gè)參考原則:

  • 編寫完代碼多問(wèn)自己一句:"真的可靠地完成目標(biāo)了嗎嗦枢?" 怎么問(wèn),寫個(gè)測(cè)試來(lái)提問(wèn)屯断。這便是 測(cè)試覆蓋文虏。
  • 編寫代碼之前先問(wèn)自己一句:"怎么樣才算完成目標(biāo)了呢?" 怎么問(wèn)殖演,同樣寫個(gè)測(cè)試來(lái)提問(wèn)氧秘。這便是 TDD + 測(cè)試覆蓋

測(cè)試能做什么

要知道測(cè)試能做什么趴久,首先我們需要知道測(cè)試是什么(它在測(cè)什么)丸相?它能給我們帶來(lái)什么價(jià)值?以及人力成本那么昂貴彼棍,我們?yōu)槭裁催€要花時(shí)間去編寫這些上不了產(chǎn)品的測(cè)試代碼灭忠?

程序員總喜歡倒騰點(diǎn)代碼來(lái)開(kāi)始一個(gè)話題:

public class StringUtils {
    public static String toUpperCase(String source) {
        if (source == null) {
            return null;
        }
        return source.toUpperCase();
    }
}


class StringUtilsTest {
    @Test
    void convert_to_upper_case() throws Exception {
        assertThat(StringUtils.toUpperCase("unit-test"), is("UNIT-TEST"));
    }
}

這一小段測(cè)試代碼所做的事情是在驗(yàn)證StringUtils#toUpperCase方法的功能正確性。

順便用一句話來(lái)形容單元測(cè)試:

開(kāi)發(fā)人員編寫一小段代碼座硕,用于檢驗(yàn)被檢測(cè)代碼的一個(gè)很小的更舞、很明確的功能是否正確。

廣義上的測(cè)試并不總是像上面這段代碼這么簡(jiǎn)單坎吻,熟為人知的 測(cè)試金字塔 將測(cè)試分為三大類缆蝉,單元測(cè)試位于測(cè)試金字塔底端,旨在傳達(dá)單元測(cè)試應(yīng)該來(lái)得更兇猛一些瘦真,而它們正是由開(kāi)發(fā)人員親手編寫出來(lái)刊头。本文也是圍繞單元測(cè)試來(lái)開(kāi)展。


測(cè)試的價(jià)值何在

經(jīng)常聽(tīng)開(kāi)發(fā)人員說(shuō):"我對(duì)我的代碼非常有信心诸尽。"理由往往充分且單一:單元測(cè)試是老大原杂,老大罩著我不怕。(當(dāng)然您机,專業(yè)的QA始終能發(fā)現(xiàn)DEV很難察覺(jué)到的Defect穿肄,難免會(huì)驚起一臉狐疑:老大不靈了嗎!回首代碼际看,覺(jué)漏某一Case)咸产。

所以單元測(cè)試能夠增強(qiáng)你寫代碼的信心。都說(shuō)自信是成功者必不可少的特質(zhì)仲闽。當(dāng)你對(duì)代碼充滿信心之后脑溢,你的潛能無(wú)形中被激發(fā)(你會(huì)發(fā)現(xiàn)你敲代碼的速度都會(huì)變快),這樣你工作效率的提高促使你更加輕松地完成工作赖欣。身心受益便會(huì)產(chǎn)生一連串良性的"蝴蝶效應(yīng)"屑彻。

測(cè)試的兩個(gè)無(wú)形價(jià)值就體現(xiàn)出來(lái)了:

1. 增強(qiáng)我們寫代碼的信心验庙。
2. 讓我們更加輕松的完成工作,身心收益社牲。

再來(lái)說(shuō)說(shuō)有形的代碼粪薛。缺陷減少了則證明你的代碼質(zhì)量提高了,代碼質(zhì)量衡量指標(biāo)總離不開(kāi)可讀性搏恤、可擴(kuò)展性违寿、可維護(hù)性。這三個(gè)指標(biāo)的增強(qiáng)反映了良好的代碼整潔度挑社、OO設(shè)計(jì)、模塊化等巡揍。實(shí)踐證明痛阻,這些良好的設(shè)計(jì)往往不是一蹴而就的,而當(dāng)你為一個(gè)類或方法編寫單元測(cè)試卻舉步維艱的時(shí)候腮敌,你就應(yīng)該考慮去改良你的設(shè)計(jì)了阱当。

理想情況下,編寫完的代碼應(yīng)該是可以工作的糜工。但現(xiàn)實(shí)并不那么美好弊添,當(dāng)你在驗(yàn)證代碼正確性的時(shí)候遇到問(wèn)題,你就不得不頻繁地啟用調(diào)式模式捌木,而調(diào)試正是吞噬你寶貴時(shí)間的惡魔油坝。此時(shí)我們要拔出單元測(cè)試這把神劍,使出渾身解數(shù)將惡魔驅(qū)趕到塵封的黑暗角落刨裆,從而縮減我們花在調(diào)式上的時(shí)間澈圈。

那么,測(cè)試的兩個(gè)有形的價(jià)值也體現(xiàn)出來(lái)了:

3. 改良我們的設(shè)計(jì)帆啃。
4. 縮減我們花在調(diào)式上的時(shí)間瞬女。

在敏捷開(kāi)發(fā)領(lǐng)域,文檔(需求文檔努潘,詳細(xì)設(shè)計(jì)文檔等)是罕見(jiàn)之物诽偷。當(dāng)一個(gè)新人半途加入項(xiàng)目的時(shí)候,在沒(méi)有太多文檔的情況下疯坤,閱讀測(cè)試代碼便是一個(gè)很好的開(kāi)始报慕。當(dāng)然,前提是我們的測(cè)試代碼必須是可靠的压怠,并且具有良好的可讀性卖子。單元測(cè)試的第五項(xiàng)不可小覷的價(jià)值就被體現(xiàn)出來(lái):

5. 測(cè)試即文檔。

不寫測(cè)試又如何

有一種聲音:"單元測(cè)試代碼寫得再漂亮刑峡,也終究不是產(chǎn)品代碼洋闽,在部署到生產(chǎn)環(huán)境時(shí)會(huì)被無(wú)情的拋棄掉玄柠!"

所以被這種聲音迷惑的人開(kāi)始信奉了長(zhǎng)(測(cè))話(試)短(少)說(shuō)(寫),短(甚)話(至)不(不)說(shuō)(寫)的信仰诫舅。這只是經(jīng)過(guò)修飾得以傳播的一種聲音羽利,而背后做支撐的總有那么幾大派系。

無(wú)辜派

1. 我并不清楚代碼的行為刊懈,你叫我怎么測(cè)試呢这弧?
2. 這些代碼命名都能夠通過(guò)編譯啊虚汛!

個(gè)性派

1. 測(cè)試代碼不是我的工作匾浪,這不應(yīng)該由專門的人去做嗎?
2. 公司請(qǐng)我來(lái)是為了寫代碼卷哩,而不是寫測(cè)試的蛋辈。

同理派

1. 如果我讓QA人員沒(méi)有工作,那么我會(huì)覺(jué)得很內(nèi)疚的将谊!

仔細(xì)推敲這三大派系冷溶,甩出幾個(gè)問(wèn)題就能讓這些借口不攻自破:

1. 如果連代碼的行為都不清楚,寫出來(lái)的代碼意義何在尊浓?
2. 通過(guò)編譯就代表能正常工作嗎逞频?
3. 你可以不寫測(cè)試,但你寫的代碼不斷被QA找出Defect栋齿,作為DEV名聲信譽(yù)何在苗胀,難道寫出可靠的代碼也不是你的職責(zé)嗎?
4. 公司的確不是雇你來(lái)寫測(cè)試的瓦堵,那公司是顧你來(lái)調(diào)試bug的嗎柒巫?
5. 試問(wèn)QA會(huì)喜歡一個(gè)交付的代碼存在很多Defect的DEV嗎?我想QA也寧愿代碼可靠到讓他ta"無(wú)事可做"谷丸,從而去做一些功能測(cè)試堡掏、性能測(cè)試、驗(yàn)收測(cè)試等刨疼。

讓我覺(jué)得值得一提的是常規(guī)派的看法:

1. 編寫單元測(cè)試太花時(shí)間了泉唁,項(xiàng)目結(jié)束時(shí)再說(shuō)吧!
2. 運(yùn)行測(cè)試時(shí)間太長(zhǎng)了揩慕!

"編寫單元測(cè)試太花時(shí)間了亭畜,等測(cè)試結(jié)束后再說(shuō)" 聽(tīng)起來(lái)是一個(gè)很合乎情理的想法。而在軟件開(kāi)發(fā)項(xiàng)目上存在一個(gè)這樣的魔咒:

一推再推的事情迎卤,往往都是不會(huì)去做的事情拴鸵。

不去做的原因可能是重視度不夠,被和諧掉了,也可能是最后想去做也沒(méi)有時(shí)間去做劲藐。不管出于什么原因八堡,不寫測(cè)試存在潛在的風(fēng)險(xiǎn)。

實(shí)踐證明聘芜,隨著時(shí)間推移兄渺,產(chǎn)品的功能性的變化趨勢(shì)受測(cè)試代碼編寫的時(shí)機(jī)的影響如下圖所示:

好想法抵擋不住現(xiàn)實(shí)的打擊,代碼庫(kù)隨著項(xiàng)目的進(jìn)展越發(fā)復(fù)雜汰现,由于沒(méi)有測(cè)試的保護(hù)挂谍,一些不良的設(shè)計(jì)偷偷溜了進(jìn)來(lái),代碼越發(fā)嬌氣瞎饲,慢慢地沒(méi)有人敢去動(dòng)它口叙。最糟糕的結(jié)果可能是,DEVs頂著巨大交付壓力嗅战,唯唯諾諾的寫著代碼妄田,而災(zāi)難正在醞釀,交付最終失敗仗哨。

所以形庭,只有當(dāng)測(cè)試代碼并行于產(chǎn)品代碼铅辞,甚至可以采用TDD厌漂。測(cè)試的幾大價(jià)值才有可能被體現(xiàn)出來(lái),從而能夠?yàn)槲覀兊漠a(chǎn)品保駕護(hù)航斟珊。

就我個(gè)人經(jīng)驗(yàn)苇倡,半TDD的編碼方式,在一個(gè)Story上所花的總時(shí)間不會(huì)多余沒(méi)有測(cè)試裸奔的代碼囤踩≈冀罚或許剛開(kāi)始會(huì)覺(jué)得有點(diǎn)拖慢節(jié)奏,操練多了堵漱,它的威力就會(huì)彰顯出來(lái)了综慎。

測(cè)試也寫了,可是運(yùn)行時(shí)間太長(zhǎng)了又帶來(lái)了另一個(gè)苦惱勤庐?

細(xì)談該苦惱可以單獨(dú)寫一篇文章了示惊。我的確見(jiàn)過(guò)測(cè)試運(yùn)行時(shí)間很長(zhǎng),每次驗(yàn)證一次跑上半個(gè)多小時(shí)愉镰。下面列舉一些測(cè)試加速的實(shí)踐:

1. 編寫更多的單元代碼來(lái)代替一些不重要的集成測(cè)試和UI測(cè)試米罚。
2. 使用Mockito、JMock等工具模擬掉依賴丈探。
3. 并行運(yùn)行測(cè)試录择,前提是讓測(cè)試之間保持相互獨(dú)立。
4. 讓CI服務(wù)器去跑更耗時(shí)的集成測(cè)試和UI測(cè)試。
5. 使用契約測(cè)試來(lái)代替微服務(wù)之間的集成測(cè)試隘竭。

單元測(cè)試運(yùn)行時(shí)間是毫秒級(jí)別的塘秦,如果耗時(shí)過(guò)長(zhǎng),你就要留意是否存在內(nèi)存泄漏货裹、資源未釋放嗤形、依賴過(guò)重或者不依賴容器而啟動(dòng)了容器的單元測(cè)試。


揮之不去的例外

編寫單元測(cè)試是一項(xiàng)成本低卻價(jià)值很高的活動(dòng)弧圆。編寫它不會(huì)花掉你太多的時(shí)間赋兵,而運(yùn)行它更是毫秒間的事情。極限編程推崇者正在使用TDD的方式詮釋著單元測(cè)試的價(jià)值和意義搔预。

它能帶給我們信心霹期,改良我們的代碼設(shè)計(jì),提升我們(DEVs)的聲譽(yù)拯田,為代碼庫(kù)保駕護(hù)航历造,為高質(zhì)量的軟件交付提供保障。但它終究不是一顆銀彈船庇。我們編寫單元測(cè)試也無(wú)非是一種價(jià)值的取舍吭产,當(dāng)它給我們帶來(lái)的價(jià)值低于我們付出的成本時(shí),我們就要保持警惕了鸭轮,比如思考以下兩個(gè)問(wèn)題:

1. 在追求漂亮的測(cè)試覆蓋率數(shù)字100%的時(shí)候臣淤,思考一下它真有那么高的價(jià)值嗎?
2. 在做快速的技術(shù)Spike(技術(shù)調(diào)研)窃爷,思考一下不寫測(cè)試是不是能讓我更快的試錯(cuò)邑蒋?

我們要理解的是單元測(cè)試背后的核心價(jià)值,從而做出正確的取舍按厘。我們要做的是編寫出有效的單元測(cè)試医吊,讓它真正地為我們創(chuàng)造價(jià)值。


注釋

  • Terminal:命令行終端
  • QA:專職測(cè)試人員
  • PM:項(xiàng)目經(jīng)理
  • DEV:開(kāi)發(fā)人員逮京,DEVs表示復(fù)數(shù)
  • OOD:面向?qū)ο笤O(shè)計(jì)
  • FOP:函數(shù)時(shí)編程
  • TDD:測(cè)試驅(qū)動(dòng)開(kāi)發(fā)
  • CI:持續(xù)集成
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末卿堂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子懒棉,更是在濱河造成了極大的恐慌草描,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,888評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件漓藕,死亡現(xiàn)場(chǎng)離奇詭異陶珠,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)享钞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門揍诽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)诀蓉,“玉大人,你說(shuō)我怎么就攤上這事暑脆∏。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,386評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵添吗,是天一觀的道長(zhǎng)沥曹。 經(jīng)常有香客問(wèn)我,道長(zhǎng)碟联,這世上最難降的妖魔是什么妓美? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,726評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮鲤孵,結(jié)果婚禮上壶栋,老公的妹妹穿的比我還像新娘。我一直安慰自己普监,他們只是感情好贵试,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著凯正,像睡著了一般毙玻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上廊散,一...
    開(kāi)封第一講書(shū)人閱讀 52,337評(píng)論 1 310
  • 那天桑滩,我揣著相機(jī)與錄音,去河邊找鬼奸汇。 笑死施符,一個(gè)胖子當(dāng)著我的面吹牛往声,可吹牛的內(nèi)容都是我干的擂找。 我是一名探鬼主播,決...
    沈念sama閱讀 40,902評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼浩销,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼贯涎!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起慢洋,我...
    開(kāi)封第一講書(shū)人閱讀 39,807評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤塘雳,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后普筹,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體败明,經(jīng)...
    沈念sama閱讀 46,349評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評(píng)論 3 340
  • 正文 我和宋清朗相戀三年太防,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了妻顶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,567評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖讳嘱,靈堂內(nèi)的尸體忽然破棺而出幔嗦,到底是詐尸還是另有隱情,我是刑警寧澤沥潭,帶...
    沈念sama閱讀 36,242評(píng)論 5 350
  • 正文 年R本政府宣布邀泉,位于F島的核電站,受9級(jí)特大地震影響钝鸽,放射性物質(zhì)發(fā)生泄漏汇恤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評(píng)論 3 334
  • 文/蒙蒙 一拔恰、第九天 我趴在偏房一處隱蔽的房頂上張望屁置。 院中可真熱鬧,春花似錦仁连、人聲如沸蓝角。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,420評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)使鹅。三九已至,卻和暖如春昌抠,著一層夾襖步出監(jiān)牢的瞬間患朱,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,531評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工炊苫, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留裁厅,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,995評(píng)論 3 377
  • 正文 我出身青樓侨艾,卻偏偏與公主長(zhǎng)得像执虹,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子唠梨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評(píng)論 2 359

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