使用Spock框架進(jìn)行單元測(cè)試 - OPEN 開(kāi)發(fā)經(jīng)驗(yàn)庫(kù)
http://www.open-open.com/lib/view/open1439793373083.html
很多人一談到單元測(cè)試就會(huì)想到xUnit框架梁钾。對(duì)于一些java新人來(lái)說(shuō),會(huì)用jUnit就是會(huì)寫(xiě)單元測(cè)試获雕,高級(jí)點(diǎn)的會(huì)搗鼓一下testng肠槽,然后就認(rèn)為自己掌握了單元測(cè)試牌废。
2.2.單元測(cè)試的痛點(diǎn)
對(duì)于新人來(lái)說(shuō)酿矢,很容易在編寫(xiě)單元測(cè)試的時(shí)候遇到這幾類(lèi)問(wèn)題:
2.2.1.單元測(cè)試的資料不夠全
這里不夠全是相對(duì)于“編碼”來(lái)說(shuō)的樱衷。介紹如何編碼创译、如何使用某個(gè)框架的書(shū)茫茫多膀曾,但是與編碼同樣重要的介紹單元測(cè)試的書(shū)卻不多县爬,翻來(lái)覆去好的也不多,并且都有一定年頭了添谊。(如果有這方面的好的資料财喳,請(qǐng)推薦給我,多謝)
很多關(guān)于編程的書(shū)籍中并沒(méi)有深入介紹如何進(jìn)行單元測(cè)試碉钠,或者僅僅介紹了最基礎(chǔ)的assert纲缓、jUnit里怎么定義一個(gè)測(cè)試函數(shù)之類(lèi)卷拘,就沒(méi)有然后了,給人的感覺(jué)是這樣:
[圖片上傳中祝高。栗弟。。(1)]
2.2.2.單元測(cè)試難以理解和維護(hù)
測(cè)試代碼不像普通的應(yīng)用程序一樣有著很明確的作為“值”的輸入和輸出工闺。舉個(gè)例子乍赫,假如一個(gè)普通的函數(shù)要做下面這件事情:
接收一個(gè)user對(duì)象作為參數(shù)
調(diào)用dao層的update方法更新用戶(hù)屬性
返回true/false結(jié)果
那么,只需要在函數(shù)中聲明一個(gè)參數(shù)陆蟆、做一次調(diào)用雷厂、返回一個(gè)布爾值就可以了。但如果要對(duì)這個(gè)函數(shù)做一個(gè)“純粹的”單元測(cè)試叠殷,那么它的輸入和輸出會(huì)有很多情況改鲫,比如其中一個(gè)測(cè)試是這樣:
假設(shè)調(diào)用dao層的update方法會(huì)返回true。
程序去調(diào)用service層的update方法林束。
驗(yàn)證一下service是不是也返回了true像棘。
無(wú)論是用什么樣的單元測(cè)試框架,最后寫(xiě)出來(lái)的單元測(cè)試代碼量也比業(yè)務(wù)代碼只多不少壶冒,我在寫(xiě)代碼過(guò)程中的經(jīng)驗(yàn)值是:要在不作弊的情況下維持比較高的單元測(cè)試覆蓋率缕题,要有三倍于業(yè)務(wù)代碼的單測(cè)代碼。
更多的代碼量胖腾,加上單測(cè)代碼并不像業(yè)務(wù)代碼那樣直觀烟零,還有對(duì)單測(cè)代碼可讀性不重視的壞習(xí)慣,導(dǎo)致最終呈現(xiàn)出來(lái)的單測(cè)代碼難以閱讀咸作,要維護(hù)更是難上加難锨阿。
同時(shí),大部分單元測(cè)試的框架都有很強(qiáng)的代碼侵入性性宏。要理解單元測(cè)試群井,首先得學(xué)習(xí)他用的那個(gè)單元測(cè)試框架,這無(wú)形中又增加了單元測(cè)試?yán)斫夂途S護(hù)的難度毫胜。
2.2.3.單元測(cè)試難以去除依賴(lài)
就像之前說(shuō)的,如果要寫(xiě)一個(gè)純粹的诬辈、無(wú)依賴(lài)的單元測(cè)試往往很困難酵使,比如依賴(lài)了數(shù)據(jù)庫(kù)、或者依賴(lài)了文件系統(tǒng)焙糟、再或者依賴(lài)了其它模塊口渔。
所以很多人在寫(xiě)單元測(cè)試時(shí)選擇依賴(lài)一部分資源,比如在本機(jī)啟動(dòng)一個(gè)數(shù)據(jù)庫(kù)穿撮。這類(lèi)所謂的“單元測(cè)試”往往很流行缺脉,但是對(duì)于多人合作的項(xiàng)目痪欲,這類(lèi)測(cè)試卻經(jīng)常容易造成混亂。
比如說(shuō)要在本地讀個(gè)文件攻礼,或者連接某個(gè)數(shù)據(jù)庫(kù)业踢,其他修改代碼的人(或者持續(xù)集成系統(tǒng)中)并沒(méi)有這些東西,所以測(cè)試也都沒(méi)法通過(guò)礁扮。最后大部分這類(lèi)測(cè)試代碼的下場(chǎng)都是用不了知举、也舍不得刪,只好被注釋掉太伊,扔在那里雇锡。
隨著開(kāi)源項(xiàng)目逐漸發(fā)展,對(duì)外部資源的依賴(lài)問(wèn)題開(kāi)始可以通過(guò)一些測(cè)試輔助工具解決僚焦,比如使用內(nèi)存型數(shù)據(jù)庫(kù)H2代替連接實(shí)際的測(cè)試數(shù)據(jù)庫(kù)锰提,不過(guò)能替代的資源類(lèi)型始終有限。
而實(shí)際工作過(guò)程中芳悲,還有一類(lèi)難以處理的依賴(lài)問(wèn)題:代碼依賴(lài)立肘。比如一個(gè)對(duì)象的方法中調(diào)用了其它對(duì)象的方法,其它對(duì)象又調(diào)用了更多對(duì)象芭概,最后形成了一個(gè)無(wú)比巨大的調(diào)用樹(shù)赛不。
很多比較舊的描述單元測(cè)試的書(shū)里寫(xiě)了一些傳統(tǒng)的辦法,這類(lèi)方法基本上是先對(duì)耦合的部分做模擬罢洲,再對(duì)結(jié)果部分做斷言踢故。例如可以通過(guò)繼承來(lái)自己做一個(gè)假的stub對(duì)象,最終用assert的方式驗(yàn)證正確性惹苗。但是這相當(dāng)于對(duì)于每種假設(shè)都要做一個(gè)假的對(duì)象殿较,而且對(duì)結(jié)果進(jìn)行驗(yàn)證也比較復(fù)雜:比如我要驗(yàn)證“更新”操作是否真的調(diào)用了dao層,那么要自己在stub對(duì)象里對(duì)調(diào)用進(jìn)行計(jì)數(shù)桩蓉,驗(yàn)證時(shí)再對(duì)計(jì)數(shù)進(jìn)行斷言淋纲,非常繁瑣。
后來(lái)出現(xiàn)了一些mock框架院究,比如java的JMockit洽瞬、EasyMock,或者M(jìn)ockito业汰。利用這類(lèi)框架可以相對(duì)比較輕松的通過(guò)mock方式去做假設(shè)和驗(yàn)證伙窃,相對(duì)于之前的方式有了質(zhì)的飛躍,但是即使用上這類(lèi)框架样漆,遇到復(fù)雜的業(yè)務(wù)代碼往往也無(wú)能為力为障。
而往往新人的代碼質(zhì)量往往不高,尤其是對(duì)代碼的拆分和邏輯的抽象還處于懵懂階段。要對(duì)這類(lèi)代碼寫(xiě)單測(cè)鳍怨,即使是工作了3呻右,4年的高級(jí)碼農(nóng)也是一個(gè)挑戰(zhàn),對(duì)新人來(lái)說(shuō)幾乎是不可能完成的任務(wù)鞋喇。這也讓很多新人有了“寫(xiě)單測(cè)很難”的感覺(jué)声滥。
所以在這里需要強(qiáng)調(diào)一個(gè)觀點(diǎn),寫(xiě)單元測(cè)試的難易程度跟代碼的質(zhì)量關(guān)系最大确徙,并且是決定性的醒串。項(xiàng)目里無(wú)論用了哪個(gè)測(cè)試框架都不能解決代碼本身難以測(cè)試的問(wèn)題,所以如果你遇到的是“我的代碼里依賴(lài)的東西太多了所以寫(xiě)不出來(lái)單測(cè)”這樣的問(wèn)題的話鄙皇,需要去看的是如何設(shè)計(jì)和重構(gòu)代碼芜赌,而不是這篇文章。
在Spring Boot項(xiàng)目中使用Spock框架 - 簡(jiǎn)書(shū)
http://www.reibang.com/p/f1e354d382cd
利用Spock伴逸、Mockito一起編寫(xiě)一些測(cè)試用例(包括對(duì)Controller的測(cè)試和對(duì)Repository的測(cè)試)缠沈,感受下Spock的使用。