偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

網(wǎng)絡(luò)架構(gòu)之路(三) 單元測(cè)試

網(wǎng)絡(luò)
在帶隊(duì)的過(guò)程中,性能的問(wèn)題還比較好解決,最消極的想法,“好啊,多一事不如少一事,你讓我不管還不簡(jiǎn)單?”,但要求寫(xiě)測(cè)試代碼,那就炸鍋了!以我的經(jīng)歷,“測(cè)試驅(qū)動(dòng)”是一個(gè)最具爭(zhēng)議的話題,沒(méi)有之一。吹捧者和反對(duì)者涇渭分明,而且都有大量的論據(jù)和證明。記得博客園曾經(jīng)有一篇文章,大意是:“公司付錢(qián)給你不是讓你寫(xiě)測(cè)試代碼的”,下面一片狂贊。

在帶隊(duì)的過(guò)程中,性能的問(wèn)題還比較好解決,最消極的想法,“好啊,多一事不如少一事,你讓我不管還不簡(jiǎn)單?”,但要求寫(xiě)測(cè)試代碼,那就炸鍋了!以我的經(jīng)歷,“測(cè)試驅(qū)動(dòng)”是一個(gè)***爭(zhēng)議的話題,沒(méi)有之一。吹捧者和反對(duì)者涇渭分明,而且都有大量的論據(jù)和證明。記得博客園曾經(jīng)有一篇文章,大意是:“公司付錢(qián)給你不是讓你寫(xiě)測(cè)試代碼的”,下面一片狂贊。

在我自己的項(xiàng)目開(kāi)始的時(shí)候,我是放棄了測(cè)試驅(qū)動(dòng)的,里面總結(jié)得很準(zhǔn)確,***的原因是“懶”。但***讓我下定決心開(kāi)始“測(cè)試驅(qū)動(dòng)”實(shí)踐的,是我一次花了兩天一夜都沒(méi)調(diào)出一個(gè)Bug,垂頭喪氣筋疲力盡之后,無(wú)可奈何的接受了這個(gè)現(xiàn)實(shí):測(cè)試還是很有用的——即使是自己寫(xiě)的代碼。我之前的系列博客,也已經(jīng)反復(fù)的強(qiáng)調(diào),架構(gòu)是一種“無(wú)奈”,是現(xiàn)實(shí)是問(wèn)題驅(qū)使你去做一些其實(shí)你本來(lái)不想做的事情。你無(wú)法理解一些看起來(lái)像“脫了褲子放屁”一樣的行為,通常只是因?yàn)槟銢](méi)有遭遇過(guò)那些現(xiàn)實(shí)那些問(wèn)題。(看看,大學(xué)能教你這些東西么?)

即使你沒(méi)有多少開(kāi)發(fā)經(jīng)驗(yàn),你也應(yīng)該能夠想象,單元測(cè)試***的問(wèn)題,就是它需要花時(shí)間花精力去寫(xiě),那么這個(gè)花費(fèi)是否值得呢?這還是由你架構(gòu)的目標(biāo)決定的,或者你的需求決定的。如果系統(tǒng)是一次成型交付使用,此后幾乎不會(huì)更改的,那么一次性的手工測(cè)試就夠了;但如果你的系統(tǒng)是會(huì)被“千錘百煉”的不斷折騰修改的,那么這個(gè)測(cè)試就是很有必要的。最簡(jiǎn)單的考慮:每一次更改,我都要手工測(cè)試一次;那還不會(huì)如我多花點(diǎn)時(shí)間,弄個(gè)“自動(dòng)化”的東西出來(lái)。單元測(cè)試,其實(shí)就可以理解為一種自動(dòng)化的測(cè)試工具。

但是“自動(dòng)化”的理由還遠(yuǎn)遠(yuǎn)不夠。因?yàn)槟泷R上想到的,每一次需求變更代碼調(diào)整,測(cè)試代碼也得相應(yīng)的改呀?沒(méi)有測(cè)試代碼,我就只需要改開(kāi)發(fā)代碼;現(xiàn)在有了單元測(cè)試,我還得再改測(cè)試代碼。本來(lái)我只維護(hù)一套代碼,現(xiàn)在我憑空增加了一套代碼也需要維護(hù),這不是增加了維護(hù)成本,不是和你“可維護(hù)性”的架構(gòu)目標(biāo)背道而馳了么?是一套代碼好維護(hù)呢,還是兩套代碼更好維護(hù)?

這是一個(gè)非常好的問(wèn)題,適用于很多情景(比如分層架構(gòu),你說(shuō)分層解耦,實(shí)際上還不是一改就得從UI層改到數(shù)據(jù)庫(kù),每一層都得改?)。我能給出的回答大概有:

一、無(wú)論有無(wú)單元測(cè)試,開(kāi)發(fā)代碼進(jìn)行修改之后,是不是都要進(jìn)行測(cè)試?沒(méi)有單元測(cè)試,并不代表你的代碼就不需要測(cè)試了,只不過(guò)是你手工的去測(cè)試了一遍而已。切記:你的工作并不只是把代碼寫(xiě)出來(lái)而已!

二、進(jìn)行手工測(cè)試,和更改單元測(cè)試,兩者的耗費(fèi)比,會(huì)根據(jù)測(cè)試重用的次數(shù)而變化。一次手工測(cè)試可能需要5分鐘跑完,更改單元測(cè)試代碼可能需要20分鐘,但如果這測(cè)試會(huì)跑100遍,單元測(cè)試完勝手工測(cè)試。

三、你說(shuō),哪里喲?什么功能會(huì)改100遍?我沒(méi)說(shuō)你的功能會(huì)改100遍,我說(shuō)的是測(cè)試會(huì)跑100遍。有區(qū)別么?你可能還在犯迷糊,是吧?好吧,我們講個(gè)故事。

有一個(gè)小伙子,他很不情愿寫(xiě)測(cè)試代碼。老板拿他沒(méi)轍啊,也沒(méi)那么多精力和他磨牙,于是老板自己寫(xiě)單元測(cè)試。這小伙子的代碼提交之前要review,老板總能一次次的找出它代碼的問(wèn)題。他改的是登錄,老板告訴他積分系統(tǒng)被他改出了問(wèn)題;他又去改積分,老板又告訴他消息通知系統(tǒng)被他改壞了;他又去改消息系統(tǒng),老板告訴他登錄還是有問(wèn)題……于是他崩潰了,“這TM什么一個(gè)爛系統(tǒng)”?最終他終于回過(guò)神來(lái)了,為什么老板總能知道這里的改動(dòng)會(huì)影響那里呢?老板的思維有這么嚴(yán)謹(jǐn)?老板躲在一旁偷笑,就不告訴你,“其實(shí)我就是跑了一遍單元測(cè)試而已”。

這個(gè)老板就是我。我故意的,就不一次性的告訴他所有的問(wèn)題,就要這樣一次次的折磨他,讓他的痛苦能刻入骨子里去。***,我還要問(wèn)他:

你現(xiàn)在對(duì)你的代碼是不是還那么自信?

如果沒(méi)有我的review(我也是靠單元測(cè)試),你能不能發(fā)現(xiàn)這些問(wèn)題?

如果我們的項(xiàng)目已經(jīng)部署到生產(chǎn)環(huán)境,而且你的改動(dòng)帶來(lái)的破壞沒(méi)有被發(fā)現(xiàn)就上線了,會(huì)帶來(lái)什么樣的后果?

這一次,他服氣了。后來(lái)他用NUnit用得麻溜麻溜的。每一次改動(dòng),如果有意想不到的未通過(guò)test case,他都會(huì)很激動(dòng)的給我張截圖,順便發(fā)發(fā)牢騷。我微笑不語(yǔ),那種滿屏綠燈通過(guò)的踏實(shí),和意外爆出紅燈之后的驚喜,沒(méi)有經(jīng)歷過(guò)的人,是無(wú)法體會(huì)的。

所以其實(shí)當(dāng)對(duì)象間的關(guān)系變得越來(lái)越錯(cuò)綜復(fù)雜,像一張密密麻麻的網(wǎng)一樣之后,一個(gè)局部的改動(dòng)就很有可能會(huì)觸發(fā)極其復(fù)雜的連鎖反應(yīng)。所以為了保險(xiǎn)起見(jiàn),所有可能相關(guān)的組件都應(yīng)該進(jìn)行測(cè)試(所謂的“回歸測(cè)試”)。這時(shí)候如果只有純粹的手工測(cè)試,會(huì)面臨兩個(gè)問(wèn)題:

難以確定測(cè)試的邊界(那些部分可能會(huì)被影響),這得我們腦袋憑空硬想啊,兄弟!

極大的測(cè)試耗費(fèi)。而且這種耗費(fèi)是相當(dāng)?shù)臒o(wú)聊繁瑣傷人心的——沒(méi)人愿意做這種事。據(jù)說(shuō)所知,現(xiàn)在很多公司測(cè)試人員的工資已經(jīng)比開(kāi)發(fā)人員還高了。為什么?簡(jiǎn)單枯燥無(wú)聊,沒(méi)人愿意做啊!

好的,我假設(shè)你已經(jīng)認(rèn)識(shí)到了單元測(cè)試的重要性,并開(kāi)始摩拳擦掌,躍躍欲試。接下來(lái)我得給你潑一大瓢冷水:?jiǎn)卧獪y(cè)試不是那么好寫(xiě)的!從某種程度上講,寫(xiě)單元測(cè)試比寫(xiě)開(kāi)發(fā)代碼還難。難得我工作的所有公司,沒(méi)有一家有過(guò)成功的案例。

大概是幾年前,我在公司修bug,老大告訴我,“你這個(gè)功能比較核心,跑一下單元測(cè)試吧”。

“哇塞!我們有單元測(cè)試?”一種高大上的感覺(jué)迅速?gòu)浡?,終于見(jiàn)到傳說(shuō)中的Unit了!

搗鼓了一會(huì),能跑了,試試看——我的個(gè)媽呀?怎么這么多紅燈?我真被嚇住了,這都是我的改動(dòng)造成的?

老大就是老大,不慌不忙,“數(shù)一下有多少個(gè)通不過(guò)?”

“啊?”我以為我聽(tīng)錯(cuò)了,數(shù)多少個(gè)通不過(guò)有什么用?得把他們?nèi)颗ㄟ^(guò)啊?!

搞了一會(huì)兒,才終于弄明白了,把我改動(dòng)前后的代碼分別跑一遍,對(duì)照一下通過(guò)失敗是不是一樣的,只要是一樣的,就OK了。比如,以前是8個(gè)通不過(guò),現(xiàn)在還是8個(gè)通不過(guò),這樣就可以了!

我一直不明白,為什么不把那8個(gè)通不過(guò)的單元測(cè)試給弄成通過(guò)呢?這樣擺著究竟算什么?直到我自己開(kāi)始寫(xiě)單元測(cè)試。坑爹啊!到處都是坑,跳出小坑進(jìn)大坑,大坑下面還連著小坑,前面是坑后面是坑,一堆一堆的連環(huán)坑……

單元測(cè)試寫(xiě)出來(lái)容易跑過(guò)難!而且跑不過(guò)的原因還不是你的開(kāi)發(fā)代碼邏輯錯(cuò)了,而是測(cè)試環(huán)境/數(shù)據(jù)出問(wèn)題。要測(cè)試,一定要有數(shù)據(jù),這個(gè)數(shù)據(jù)的構(gòu)建,完全不是我們所想象的那么簡(jiǎn)單。以我們創(chuàng)業(yè)家園項(xiàng)目里的積分系統(tǒng)為例,假設(shè)一個(gè)簡(jiǎn)單的需求:博客被點(diǎn)贊,博客的作者應(yīng)該獲得一定積分,該積分?jǐn)?shù)量是由點(diǎn)贊人目前所有的可用幣轉(zhuǎn)換而得來(lái)的(已簡(jiǎn)化,具體可參考文檔:積分)。要準(zhǔn)備的數(shù)據(jù)就有:博客一篇,要有作者,作者已有積分;點(diǎn)贊人一名,有一定數(shù)量可用幣。如果只是這樣,還可以接受,但其實(shí)下面會(huì)有一堆的問(wèn)題:

作者的積分從哪里來(lái)?我們的開(kāi)發(fā)代碼,出于封裝的考慮,用戶的積分是只讀的,你單元測(cè)試怎么設(shè)這個(gè)值?

要么寫(xiě)代碼,模擬作者通過(guò)其他行為(發(fā)布文章回答問(wèn)題等)獲得積分,這將開(kāi)啟新一輪噩夢(mèng);

如果用Mock或者反射強(qiáng)行設(shè)置,事實(shí)上省略了作者獲得積分的歷史,所以用戶“積分歷史”為null,之后對(duì)其“加積分”時(shí),就會(huì)報(bào)異常。

更坑的是,你以為你什么都處理好了的時(shí)候,你突然悲哀的發(fā)現(xiàn),這個(gè)博客得首先“被發(fā)布”,而博客一經(jīng)發(fā)布,其作者就獲得了一定數(shù)量的積分,所以你以前設(shè)置的積分又變了!

……

點(diǎn)贊人的可用幣,同樣可能遇到類(lèi)似的問(wèn)題??捎脦旁趺丛O(shè)置,設(shè)置之后會(huì)不會(huì)在跑測(cè)試時(shí)被意外更改?

點(diǎn)贊的行為,被封裝成一個(gè)方法,運(yùn)行這個(gè)方法,會(huì)檢查點(diǎn)贊人之前是否已經(jīng)對(duì)該文章點(diǎn)過(guò)贊,所以還應(yīng)該有一個(gè)“點(diǎn)贊歷史記錄”,哪怕是空的,都得new一個(gè),否則就空異常

……

反正當(dāng)時(shí)是寫(xiě)得我直接摔了鼠標(biāo)!寫(xiě)得憋屈啊!而且我還是完全隔絕了數(shù)據(jù)庫(kù)的,真不知道那些要從數(shù)據(jù)庫(kù)里取數(shù)據(jù)來(lái)跑單元測(cè)試的,是怎么做的?這時(shí)候我一下子就明白了,實(shí)際工作中加班趕進(jìn)度,一個(gè)接一個(gè)的填坑,連重構(gòu)的時(shí)間都沒(méi)有,怎么可能還擠得出時(shí)間來(lái)寫(xiě)單元測(cè)試?就算開(kāi)始雄心勃勃的寫(xiě)了,隨著系統(tǒng)日益復(fù)雜,維護(hù)單元測(cè)試的成本也與日俱增,甚至復(fù)雜度更甚開(kāi)發(fā),所以放棄也就成了絕大多數(shù)項(xiàng)目的唯一選擇。

在公司上班么,大多數(shù)人都是這樣的,能推就推。我們開(kāi)發(fā)寫(xiě)完了代碼,基本上能跑了,就該交給測(cè)試人員了呀!天經(jīng)地義的嘛,是不是?而且測(cè)試的時(shí)間是不會(huì)計(jì)算到我的項(xiàng)目開(kāi)發(fā)時(shí)間里的,我總算是按時(shí)完成了開(kāi)發(fā)任務(wù)。累壞了,休息一下,讓測(cè)試的忙活去吧,哈哈……

但我是個(gè)光桿司令,我沒(méi)測(cè)試人員啊!曾經(jīng)有那么一兩個(gè)時(shí)候,我真準(zhǔn)備招一兩個(gè)測(cè)試人員的。但好在我天生的節(jié)儉美德(也就是“摳”啦)讓我冷靜下來(lái)。我就想?。簻y(cè)試只能告訴你出了bug,不能告訴你根源啊。沒(méi)有單元測(cè)試,我單步調(diào)試,不也折騰了兩天了么?這是系統(tǒng)本身的復(fù)雜性,或者代碼組織的不合理造成的,不能歸咎于單元測(cè)試。不還是有這么多開(kāi)源代碼都有詳盡的單元測(cè)試么?他們是怎么做到的呢?在單元測(cè)試上的付出,最終一定會(huì)獲得超值回報(bào)!想想沒(méi)有單元測(cè)試的公司,那超級(jí)龐大的測(cè)試團(tuán)隊(duì),或者四處冒煙的系統(tǒng),你愿意走這么一條路么?

所以我不斷的告誡自己,不要著急,冷靜細(xì)致。終于一步步抽絲剝繭,把這一團(tuán)亂麻一點(diǎn)點(diǎn)的歸納整理,最終還真被我找到了一條路子,一個(gè)個(gè)的單元測(cè)試都慢慢完成通過(guò)了,開(kāi)發(fā)代碼里潛在的一些問(wèn)題也浮出水面,被我一個(gè)個(gè)的消滅。***再跑一遍單元測(cè)試,一路綠燈,哈哈!更奇跡的是,困擾我兩天的bug不知道什么時(shí)候消失了?

后來(lái),我看到這樣一種說(shuō)法:可測(cè)試的代碼不一定是好代碼,但壞代碼幾乎是不可能被測(cè)試的。深以為然!深度耦合的代碼,寫(xiě)他們的單元測(cè)試,難于上青天;但反過(guò)來(lái),我們可以以可測(cè)試為標(biāo)準(zhǔn),不斷的完善重構(gòu)開(kāi)發(fā)代碼,只要這樣堅(jiān)持下來(lái),最終代碼的質(zhì)量怎么都不會(huì)差到哪里去。

所以,于我而言,單元測(cè)試是否有價(jià)值的爭(zhēng)論可以休矣!不如換個(gè)角度,想一想,怎樣才能把單元測(cè)試堅(jiān)持下去。

***,如果有心的同學(xué)就會(huì)注意到,我一直用的是“單元測(cè)試”,而不是“測(cè)試驅(qū)動(dòng)”。因?yàn)闇y(cè)試驅(qū)動(dòng)是一個(gè)更廣闊的概念,是一個(gè)更嶄新的天地!單元測(cè)試只是其中的一小部分,在下一篇博客,我會(huì)講解我是如何試著將測(cè)試驅(qū)動(dòng)的概念運(yùn)用到項(xiàng)目開(kāi)發(fā)管理中去的。這里,需要強(qiáng)調(diào)的一點(diǎn):先寫(xiě)測(cè)試。

一上手就寫(xiě)開(kāi)發(fā)代碼,寫(xiě)完了才寫(xiě)單元測(cè)試。這是很多開(kāi)發(fā)人員的習(xí)慣,我也經(jīng)常犯這樣的毛病,一不留神就忘了。這樣做***的問(wèn)題就是,沒(méi)有真正實(shí)現(xiàn)“測(cè)試驅(qū)動(dòng)”。你實(shí)際上還是由開(kāi)發(fā)在驅(qū)動(dòng),那么很自然的,測(cè)試照著開(kāi)發(fā)的if...else...寫(xiě)一遍,有什么意義呢?這樣做下去,就會(huì)不斷的強(qiáng)化“測(cè)試無(wú)用累贅”的印象,因?yàn)闇y(cè)試就是簡(jiǎn)單的把開(kāi)發(fā)代碼重寫(xiě)一遍而已。我開(kāi)的藥方是:

單元測(cè)試代碼和開(kāi)發(fā)代碼由不同的人員編寫(xiě)

如果做不到上面一點(diǎn),先寫(xiě)單元測(cè)試

如果連上面一點(diǎn)也做不到,直到出了bug了再寫(xiě)單元測(cè)試

第三條可能有同學(xué)無(wú)法理解,不是說(shuō)單元測(cè)試很重要么?為什么要等到出了bug才寫(xiě)?答案是:偷懶唄!記住,我們程序員是世界上最懶的人,沒(méi)意義的事從來(lái)不做!你先寫(xiě)開(kāi)發(fā)代碼再寫(xiě)測(cè)試真的沒(méi)意義,沒(méi)意義就干脆不要做了。但你可以開(kāi)啟“樂(lè)觀模式”(或者“Lazy模式”?),先樂(lè)觀的認(rèn)為,我的代碼沒(méi)問(wèn)題,或許真的就沒(méi)問(wèn)題呢,是吧?如果真出了問(wèn)題,做一個(gè)補(bǔ)救,這個(gè)時(shí)候就應(yīng)該用單元測(cè)試把這個(gè)問(wèn)題表現(xiàn)出來(lái),因?yàn)樗鶕?jù)墨菲定律,它這里出了問(wèn)題,以后就很有可能繼續(xù)出問(wèn)題。這個(gè)時(shí)候,就不要再偷懶了。

責(zé)任編輯:何妍 來(lái)源: 博客園
相關(guān)推薦

2017-01-16 12:12:29

單元測(cè)試JUnit

2017-01-14 23:26:17

單元測(cè)試JUnit測(cè)試

2017-01-14 23:42:49

單元測(cè)試框架軟件測(cè)試

2020-08-18 08:10:02

單元測(cè)試Java

2017-03-23 16:02:10

Mock技術(shù)單元測(cè)試

2021-05-05 11:38:40

TestNGPowerMock單元測(cè)試

2023-07-26 08:58:45

Golang單元測(cè)試

2011-07-04 18:16:42

單元測(cè)試

2020-05-07 17:30:49

開(kāi)發(fā)iOS技術(shù)

2011-05-16 16:52:09

單元測(cè)試徹底測(cè)試

2023-09-27 23:43:51

單元測(cè)試Spring

2017-02-23 15:59:53

測(cè)試MockSetup

2011-04-18 13:20:40

單元測(cè)試軟件測(cè)試

2012-05-17 09:09:05

Titanium單元測(cè)試

2009-09-25 10:33:25

Hibernate單元

2020-09-30 08:08:15

單元測(cè)試應(yīng)用

2010-01-28 15:54:19

Android單元測(cè)試

2011-06-14 15:56:42

單元測(cè)試

2024-07-29 12:12:59

2009-09-01 10:20:06

protected方法單元測(cè)試
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)