讓我們一起聊聊單元測(cè)試的恩怨
單元測(cè)試是一個(gè)偉大的發(fā)明,同時(shí)也是一個(gè)操蛋的發(fā)明。只要團(tuán)隊(duì)碰它,幾乎很難全身而退。
如果是我們自己寫的代碼,那么,寫寫單元測(cè)試也無傷大雅。但我們絕大多數(shù)人,都是跟在別人后面打掃狗屎,或者是留給別人一堆狗屎。這時(shí)候,單元測(cè)試寫起來,就有一種不情不愿的味道。
沒錯(cuò),就是不想寫!
為了應(yīng)付所謂的指標(biāo),我們要給那些遺留代碼,將要發(fā)臭的代碼上一劑良藥:那就是自動(dòng)化。假如這些糟心的代碼,大部分交給機(jī)器去寫,我想很多人是非常樂意的。
squaretest
有很多這樣的工具,比如IDEA自帶的。但是它只能生成一些表面功夫的東西,也就是生成一個(gè)骨架而已。
說實(shí)話,并沒有什么鳥用。根本就沒減少我多少的工作量,該覆蓋不到的代碼,還是覆蓋不到。
這個(gè)時(shí)候,我們需要更高級(jí)一點(diǎn)的工具。經(jīng)過測(cè)試,現(xiàn)在瞄準(zhǔn)了squaretest。
在IDEA的插件安裝界面中,找到squaretest并安裝之,你就會(huì)擁有這個(gè)功能。
重啟IDEA之后,從你的屎山中,找到最臭的那一塊,然后就可以在菜單中找到這個(gè)工具,生成代碼。
中間的話,可能會(huì)讓你選擇一下語言,選擇一下模版之類的,這對(duì)于一個(gè)搞軟件的來說并不是難事,所以這里也不再啰嗦。
好家伙,足足給我生成了上萬行的test代碼。這時(shí)候,無論是交給QA看,還是交給分析工具去玩,都能閃瞎它們的狗眼。
hehehehehehe....漂亮!
報(bào)錯(cuò)不少,還得微調(diào)一下參數(shù)。但大多數(shù)代碼已經(jīng)生成好了,已經(jīng)節(jié)約了很大的力氣了。
其他工具
這貌似不是一個(gè)好的賽道。因?yàn)楹芏喙ぞ叨疾辉趺淳S護(hù)了,或者不怎么好用。用愛發(fā)電越來越行不通了。
比如JUnitGenerator2.0,連JUnit5都不支持;AgitarOne,雖然只有30天的試用期,但主頁(yè)也和上古怪獸一樣;Randoop的使用,根本就不是為人類設(shè)計(jì)的;Analytix被google收購(gòu)后,幾乎進(jìn)入了墳?zāi)埂?/p>
squaretest,可以說是非常好用了。
你需要單元測(cè)試么?
很多人沒得選,因?yàn)檫@是硬指標(biāo)。如果你的工作流程有問題,單元測(cè)試不但不能增彩,反而會(huì)成為累贅。
大多數(shù)情況下,單元測(cè)試不會(huì)減少bug,它們會(huì)根據(jù)bug進(jìn)行調(diào)整,以適應(yīng)正常代碼;另外,如果你的代碼都是一些簡(jiǎn)單的CRUD,寫單元測(cè)試看不到任何有益的地方。
這個(gè)現(xiàn)狀,還是要從根源上找原因。
中國(guó)式需求,變化奇快,臨時(shí)需求多,要求快速交付。這些功能,往往復(fù)雜性比較低,編寫的代碼并不會(huì)產(chǎn)生過多的bug;由于變化快,編寫的單元測(cè)試也沒有通用的可能性;一次性的代碼,寫完之后可能永遠(yuǎn)不再修改,被扔在一個(gè)遺忘的角落。
要寫單元測(cè)試,你要確保你的單元測(cè)試多年之后還可以用。而不是等到項(xiàng)目尾聲,為了達(dá)到指標(biāo)而集中補(bǔ)充單元測(cè)試。單元測(cè)試要想發(fā)揮它的價(jià)值,需要在一開始就創(chuàng)建相關(guān)的代碼,捫心自問,很多團(tuán)隊(duì)是做不到這一點(diǎn)的。
做不到,就不要裝。
單元測(cè)試并不簡(jiǎn)單
有意思的是,即使環(huán)境達(dá)到了要求,所有的接口都提前設(shè)計(jì)了,且保持較少的變動(dòng),我們依然無法推行單元測(cè)試。
單元測(cè)試從來不是因?yàn)閷憜卧獪y(cè)試有多困難,而是大多數(shù)代碼,是無法寫出好的單元測(cè)試的。
在TDD(Test-Driven Development,測(cè)試驅(qū)動(dòng)開發(fā))模式下,測(cè)試的動(dòng)作比開發(fā)早,屬于預(yù)先設(shè)計(jì)接口定義的范疇。如果你在后期對(duì)接口進(jìn)行了較多的變更,這種方式同樣會(huì)讓開發(fā)人員變的痛苦不堪。
單元測(cè)試需要配合極限編程,經(jīng)常對(duì)代碼進(jìn)行重構(gòu)。這是設(shè)計(jì)腐化之后的一種補(bǔ)救式措施。但很多情況下,大家都害怕、拒絕對(duì)舊代碼進(jìn)行修改。工期和穩(wěn)定性是常見的借口,這些借口看起來比擴(kuò)展性和可測(cè)試性看起來更正常一些,也更能說服高層進(jìn)行決策。
沒有幾個(gè)技術(shù)決策者,能夠在銷售、產(chǎn)品、老板的重重壓力下保持初心,做這種長(zhǎng)遠(yuǎn)性的規(guī)劃。所以說單元測(cè)試肯定是有用的,但卻缺乏實(shí)施的土壤。按時(shí)上線、提前上線、bug數(shù)量,這些常見的指標(biāo),只反映了結(jié)果,那些去改進(jìn)這些結(jié)果的措施,短期效應(yīng)不是很明顯的話,很容易就胎死腹中。
單元測(cè)試還阻礙開發(fā)人員重構(gòu)的動(dòng)力。因?yàn)橹貥?gòu)意味著要?jiǎng)雍芏嗟臏y(cè)試代碼,往往很多人偷偷一評(píng)估,就放棄了。
堅(jiān)持對(duì)的事情
選擇一個(gè)優(yōu)秀的團(tuán)隊(duì),是非常重要的。大家都很專業(yè),不會(huì)虧待你所信仰的正確。專業(yè)的人才在二流子團(tuán)隊(duì)中,會(huì)像一個(gè)小丑一樣無助,大多數(shù)習(xí)以為常的經(jīng)驗(yàn),幾乎無法實(shí)施。
讓人欣慰的是,追求原則的團(tuán)隊(duì)還是有的,正確的方式可以避免很多曲折的路線,拋掉技術(shù)債所造成的負(fù)面影響。能夠加入這些團(tuán)隊(duì),是非常幸福的事情。
作為程序員,應(yīng)該時(shí)刻保持這種好的習(xí)慣,不要因?yàn)橼s工,忽略了代碼的重構(gòu)和測(cè)試。這些是一個(gè)專業(yè)的技術(shù)人員應(yīng)有的素質(zhì),而不是寄希望于公司的大環(huán)境中。這些好的習(xí)慣,就像人的氣質(zhì)一樣讓人著迷,最終會(huì)讓你超脫于其他人而受益。
作為技術(shù)管理者,你要正確評(píng)估自己的公司環(huán)境,是不是具有單元測(cè)試的生長(zhǎng)土壤。即使你明白單元測(cè)試是有益的,你也不得不做一些取舍。尤其是你判斷項(xiàng)目只不過是你的墊腳石,3年之后肯定不會(huì)在自己的手里,你更會(huì)任由它自我腐爛掉。如此情況,大家都心知肚明,沒人會(huì)對(duì)你說三道四。
作為非技術(shù)管理人員,當(dāng)有人為你提出類似這種耗費(fèi)工期的,長(zhǎng)遠(yuǎn)有益的建議,不要著急否定。看一看其他優(yōu)秀的企業(yè),是不是也曾因這些短暫的原地踏步而受益過。無知并不可怕,可怕的是不相信專業(yè)。如果你肯定了,給予支持,而不要半途而廢。有意思的是,半途而廢最終并不會(huì)廢止,它同樣會(huì)蛻變?yōu)樾问街髁x,將一件美好的事情硬生生變成指標(biāo)。
End
單元測(cè)試代碼是無聊的、枯燥的,尤其是為別人寫的代碼補(bǔ)充單元測(cè)試。通常情況下,如果不發(fā)生bug,沒有人會(huì)閑的蛋疼去動(dòng)那一堆堆的屎山,除非是不自量力的小牛犢。
這個(gè)時(shí)候,一個(gè)得心應(yīng)手的工具,自動(dòng)幫你完成這些操蛋的工作,讓你的單元測(cè)試代碼擁有和屎山一樣的生命周期,不得不說是一件快事。
作者簡(jiǎn)介:小姐姐味道 (xjjdog),一個(gè)不允許程序員走彎路的公眾號(hào)。聚焦基礎(chǔ)架構(gòu)和Linux。十年架構(gòu),日百億流量,與你探討高并發(fā)世界,給你不一樣的味道。我的個(gè)人微信xjjdog0,歡迎添加好友,進(jìn)一步交流。