當(dāng)我們談?wù)揢nit Test時我們在談?wù)撌裁矗?/h1>

原創(chuàng)文章渺蒿,轉(zhuǎn)載請注明出處

作為一個實際寫代碼的Coder,老代碼能不碰就不碰---我舉雙手贊成值纱,既沒有UT鳞贷,邏輯又混在一起,天知道改完以后會出什么Bug虐唠。
但是對于團(tuán)隊來講搀愧,如果明確知道這個模塊無法測試、無法被很好的修改疆偿,那么是時候把這部分代碼提上重構(gòu)的日程了咱筛。

一. 什么是Unit Test

直譯:面向獨立單元的測試方法。
單單這一句話我們心里有就有了疑問:什么是獨立單元杆故,或者什么樣的代碼才算一個獨立單元迅箩?
為了回答這個問題,這里引用一下wikipedia的解釋:

Intuitively, one can view a unit as the smallest testable part of an application.
https://en.wikipedia.org/wiki/Unit_testing

我們來抓一下重點:

  1. 單元处铛,對于不同的編程語言饲趋,單元的定義并不相同拐揭。在面向過程的語言中(C等),單元通常被定義為一個函數(shù)(Function)奕塑;而在面向?qū)ο蟮木幊陶Z言中(Java等)堂污,單元往往指一個類(也可指代具體的方法Method)。
  2. 最小的爵川,小到無法再拆分敷鸦,這個單元只做了一件事。
  3. 可測試的寝贡,這個單元應(yīng)該有明確的輸入和輸出扒披,并且在輸入確定時,我們應(yīng)該能夠預(yù)測輸出的情況圃泡。

二. Unit Test要達(dá)到的目標(biāo)

從工程師的角度來看碟案,一些童鞋可能會覺得寫Unit Test是枯燥切無意義的。工程期就那么幾天颇蜡,產(chǎn)品經(jīng)理又不停的改功能价说,哪有心情和時間來寫UT?
這種想法可以說對也可以說不對风秤。首先鳖目,面對有限的時間和變動的需求,為所有代碼寫UT是不現(xiàn)實的缤弦。但是不是UT就真的是枯燥且無意義的呢---也不是领迈。至少從我的角度來看,一個項目的UT需要起到以下三個作用碍沐。

  • 檢查出明顯的Bug
  • 為如何使用函數(shù)(單元)提供樣例
  • 為了重構(gòu)

可能有人會說狸捅,為了檢查Bug,這不廢話嗎累提。尘喝。。當(dāng)然我相信在座的各位對于如何在UT中檢查Bug都有兩把刷子的斋陪,而這恰好也不是我想討論的重點朽褪,但我們還是需要注意:UT并不能檢查出所有Bug,對于無法預(yù)知的用戶輸入无虚,UT能做的只是在我們所考慮到的情況下鞍匾,避免一些明顯的錯誤。但是對我們沒有考慮到的情況-----告辭骑科。橡淑。。
這里著重討論一下后面兩點:

  1. 提供樣例咆爽,有的童鞋習(xí)慣在函數(shù)上面寫上一大段的注釋梁棠,有時候看業(yè)務(wù)代碼搞得像在讀JDK源碼置森。出現(xiàn)這種情況,我認(rèn)為可能有兩個原因:
    第一符糊,代碼沒有做好拆分工作凫海,將過多的邏輯糅合在一個類(方法)中,需要考慮的輸入情況異常多男娄,直觀上根本無從下手來寫UT行贪。
    針對這種情況,我們應(yīng)該考慮使用一些設(shè)計手法將代碼拆分成獨立的可測試的最小單元模闲。
    第二建瘫,這個單元已經(jīng)是最小的了,但是它確實有許多邏輯需要處理尸折。首先啰脚,我認(rèn)為如果真的拆分成了最小單元,那需要處理的邏輯應(yīng)該并不會太多实夹,至少不需要寫一段話來描述它要做的事情橄浓。即使需要告知后來的開發(fā)這里做了什么,一個完整的UT也比閱讀一大段文字來的實際亮航。

  2. 為了重構(gòu)
    許多工程師對重構(gòu)這個詞有個錯誤的印象---提到重構(gòu)荸实,我們就需要對代碼做翻天覆地的變化,甚至覺得是把以前的代碼廢棄掉重新寫缴淋。
    最近閱讀了一些重構(gòu)方面的書籍准给,有一個讓我印象深刻的觀點:重構(gòu)應(yīng)該要貫穿整個產(chǎn)品的生命周期。有因為業(yè)務(wù)擴(kuò)展與變動進(jìn)行重構(gòu)宴猾,也有一個Bug導(dǎo)致需要對代碼結(jié)構(gòu)進(jìn)行重構(gòu)。而但凡涉及到重構(gòu)叼旋,我們就需要UT為我們保駕護(hù)航仇哆。
    在對代碼進(jìn)行重構(gòu)時,UT就像一張保護(hù)網(wǎng)夫植,防止我們破壞掉原有的邏輯讹剔。對于一個規(guī)模不大的核心模塊,在上線之初我們就為它編寫了詳細(xì)的UT用例详民,使其滿足我們所考慮的各種情況延欠。但是隨著業(yè)務(wù)的增長,我們可能需要對模塊內(nèi)部進(jìn)行優(yōu)化沈跨,使其有更高的性能由捎。得益于我們之前的工作,每重構(gòu)完一段代碼饿凛,我們都運(yùn)行一遍UT狞玛,如果通過软驰,大概率說明我們沒有“搞破壞”。當(dāng)整個部分重構(gòu)完成心肪,我們需要反過來對UT進(jìn)行審視锭亏,之前沒有考慮到的情況、新的代碼都需要進(jìn)行覆蓋硬鞍。
    這樣我們的代碼保護(hù)網(wǎng)就會越來越牢固慧瘤。可以想象固该,如果沒有UT锅减,我們新來的開發(fā)人員在修改老功能時是多么的緊張,因為他不知道自己也許不經(jīng)意間破壞了原有的邏輯蹬音。

三. 哪些地方需要Unit Test

正如前文所述上煤,并不是所有地方都需要寫UT,從某種意義上講著淆,UT應(yīng)該越少越好劫狠,前提是系統(tǒng)拆分夠精確,關(guān)注點的測試夠詳細(xì)永部。
針對實際的項目独泞,我對代碼進(jìn)行了一些分類:

  1. 瑣碎的代碼,例如getter/setter,toString苔埋。除非有特殊邏輯懦砂,否則為這些代碼寫UT沒有意義。
  2. 無明確意義组橄、承上啟下的代碼荞膘,例如一些只做透傳作用的Service等。(當(dāng)然玉工,個人認(rèn)為這種只做透傳的代碼應(yīng)該盡量少)
  3. 具有算法和業(yè)務(wù)邏輯的代碼羽资。這部分代碼我們應(yīng)該重點關(guān)注,最為典型的就是一些公共類遵班,基礎(chǔ)Service層等屠升。盡量為它們寫上詳盡的UT,造福后人狭郑。
  4. 最后一類是非常復(fù)雜的代碼腹暖。各種復(fù)雜邏輯交織在一起,牽一發(fā)而動全身翰萨,我們本能地可以感覺到代碼中的“壞味道”脏答。對于這類代碼,首先應(yīng)該考慮做代碼的清理工作(由粗到細(xì)重構(gòu)),過程中不斷為小單元注入Unit Test以蕴,最后形成一張嚴(yán)密的代碼保護(hù)網(wǎng)糙麦,將原來的代碼切碎為可維護(hù)的代碼。

在實際開發(fā)中對第四點可能有些爭議丛肮。對于公司或者團(tuán)隊來講赡磅,一個產(chǎn)品的代碼不可能始終是一個人負(fù)責(zé),但往往新的同事接手老代碼時不知道從哪下手宝与。我的第一份工作焚廊,當(dāng)我作為一個畢業(yè)生,第一次接手一個完整的項目代碼习劫,一上來就是一個好幾千行的函數(shù)咆瘟,其中包含的各種請求的發(fā)送,變量的隨意命名與重復(fù)使用诽里,還有各種復(fù)制粘貼的痕跡袒餐。你能想象對于一個新人來講這是多么的絕望嗎。
作為一個實際寫代碼的Coder谤狡,老代碼能不碰就不碰---我舉雙手贊成间涵,既沒有UT匹中,邏輯又混在一起秸妥,天知道改完以后會出什么Bug七蜘。
但是對于團(tuán)隊來講,如果明確知道這個模塊無法測試捕仔、無法被很好的修改匕积,那么是時候把這部分代碼提上重構(gòu)的日程了。

其實我認(rèn)為代碼的組織與規(guī)范(包括UT)是開發(fā)流程中非常重要的一部分榜跌,在一開始我們就應(yīng)該定期進(jìn)行CodeReview闪唆,避免寫出無法維護(hù)的代碼。一個團(tuán)隊可能會負(fù)責(zé)多個項目钓葫,這些項目應(yīng)該是屬于團(tuán)隊中的每一個人悄蕾,而不是誰負(fù)責(zé),其他人就可以不管瓤逼。我們應(yīng)該把項目的Dev和Ops視為自己的責(zé)任笼吟。有太多的項目由于走形式的CodeReview库物、沒有UT霸旗、沒有文檔,導(dǎo)致最后無法維護(hù)戚揭,這是我們都不想看到的诱告。

UT是不可能寫的,這輩子都不可能寫的民晒,老代碼就只能讓它勉強(qiáng)運(yùn)行下去這樣子~

四. 怎么做Unit Test

至于如何做UT精居,網(wǎng)上一搜一大把的教程锄禽,這里就不贅述了,只是列幾條個人總結(jié)的值得注意的點:

  • 多組數(shù)據(jù)(考慮周全)->正常業(yè)務(wù)測試靴姿,邊界條件測試
  • 不要誤用Mock工具沃但,理清需要被Mock的對象
  • 整體覆蓋率沒有意義,但是關(guān)鍵業(yè)務(wù)代碼覆蓋率很重要
  • 運(yùn)維時:每一個BugReport都應(yīng)有一個對應(yīng)的UT
  • UT并不是越多越好佛吓,而是對于核心代碼宵晚、有意義的錯誤,UT越詳細(xì)越好
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者

  • 序言:七十年代末维雇,一起剝皮案震驚了整個濱河市淤刃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吱型,老刑警劉巖逸贾,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異津滞,居然都是意外死亡铝侵,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門据沈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來哟沫,“玉大人,你說我怎么就攤上這事锌介∈染鳎” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵孔祸,是天一觀的道長隆敢。 經(jīng)常有香客問我,道長崔慧,這世上最難降的妖魔是什么拂蝎? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮惶室,結(jié)果婚禮上温自,老公的妹妹穿的比我還像新娘。我一直安慰自己皇钞,他們只是感情好悼泌,可當(dāng)我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著夹界,像睡著了一般馆里。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天鸠踪,我揣著相機(jī)與錄音丙者,去河邊找鬼。 笑死营密,一個胖子當(dāng)著我的面吹牛械媒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播评汰,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼滥沫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了键俱?” 一聲冷哼從身側(cè)響起兰绣,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎编振,沒想到半個月后缀辩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡踪央,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年臀玄,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片畅蹂。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡健无,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出液斜,到底是詐尸還是另有隱情累贤,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布少漆,位于F島的核電站臼膏,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏示损。R本人自食惡果不足惜渗磅,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望检访。 院中可真熱鬧始鱼,春花似錦、人聲如沸脆贵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丹禀。三九已至状勤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間双泪,已是汗流浹背持搜。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留焙矛,地道東北人葫盼。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像村斟,于是被迫代替她去往敵國和親贫导。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,055評論 2 355

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