目錄 1 單元測(cè)試自己認(rèn)為,單元測(cè)試最重要的作用有如下兩點(diǎn) ①開(kāi)發(fā)人員實(shí)現(xiàn)某個(gè)功能或者修補(bǔ)了某個(gè)bug,如果有相應(yīng)的單元測(cè)試支持的話,開(kāi)發(fā)人員可以馬上通過(guò)運(yùn)行單元測(cè)試來(lái)驗(yàn)證之前完成的代碼是否正確,而不需要反復(fù)通過(guò)發(fā)布war包、啟動(dòng)jboss、通過(guò)瀏覽器輸入數(shù)據(jù)等繁瑣的步驟來(lái)驗(yàn)證所完成的功能 ②保證你最后的代碼修改不會(huì)破壞之前代碼的功能。項(xiàng)目越做越大,代碼越來(lái)越多,特別涉及到一些公用接口之類的代碼或是底層的基礎(chǔ)庫(kù),誰(shuí)也不敢保證這次修改的代碼不會(huì)破壞之前的功能,所以與此相關(guān)的需求會(huì)被擱置或推遲,由于不敢改進(jìn)代碼,代碼也變得越來(lái)越難以維護(hù),質(zhì)量也越來(lái)越差。而單元測(cè)試就是解決這種問(wèn)題的很好方法(不敢說(shuō)最好的)。由于代碼的歷史功能都有相應(yīng)的單元測(cè)試保證,修改了某些代碼以后,通過(guò)運(yùn)行相關(guān)的單元測(cè)試就可以驗(yàn)證出新調(diào)整的功能是否有影響到之前的功能。當(dāng)然要實(shí)現(xiàn)到這種程度需要很大的付出,不但要能夠達(dá)到比較高的測(cè)試覆蓋率,而且單元測(cè)試代碼的編寫(xiě)質(zhì)量也要有保證 2 Junit測(cè)試框架2.1 Junit是什么JUnit是一個(gè)Java語(yǔ)言的單元測(cè)試框架。它由Kent Beck和Erich Gamma建立,逐漸成為源于Kent Beck的sUnit的xUnit家族中最為成功的一個(gè)JUnit有它自己的JUnit擴(kuò)展生態(tài)圈。多數(shù)Java的開(kāi)發(fā)環(huán)境都已經(jīng)集成了JUnit作為單元測(cè)試的工具。 注意:Junit 測(cè)試也是程序員測(cè)試,即所謂的白盒測(cè)試,它需要程序員知道被測(cè)試的代碼如何完成功能,以及完成什么樣的功能 2.2 Junit 能做什么?我們知道 Junit 是一個(gè)單元測(cè)試框架,那么使用 Junit 能讓我們快速的完成單元測(cè)試。 通常我們寫(xiě)完代碼想要測(cè)試這段代碼的正確性,那么必須新建一個(gè)類,然后創(chuàng)建一個(gè) main() 方法,然后編寫(xiě)測(cè)試代碼。如果需要測(cè)試的代碼很多呢?那么要么就會(huì)建很多main() 方法來(lái)測(cè)試,要么將其全部寫(xiě)在一個(gè) main() 方法里面。這也會(huì)大大的增加測(cè)試的復(fù)雜度,降低程序員的測(cè)試積極性。而 Junit 能很好的解決這個(gè)問(wèn)題,簡(jiǎn)化單元測(cè)試,寫(xiě)一點(diǎn)測(cè)一點(diǎn),在編寫(xiě)以后的代碼中如果發(fā)現(xiàn)問(wèn)題可以較快的追蹤到問(wèn)題的原因,減小回歸錯(cuò)誤的糾錯(cuò)難度。 3 Junit測(cè)試的局限性1、在某些非常復(fù)雜的業(yè)務(wù)邏輯,會(huì)準(zhǔn)備大量的數(shù)據(jù)。 2、有的時(shí)候會(huì)依賴數(shù)據(jù)庫(kù),中間件、文件系統(tǒng)等外部環(huán)境,這個(gè)時(shí)候我們不能控制這些外部依賴的對(duì)象。 試想一下,如果我們依賴真實(shí)的數(shù)據(jù)庫(kù)環(huán)境,那么每次的單元測(cè)試結(jié)果可能都是不一樣的 為了解決上述兩個(gè)問(wèn)題,我們需要使用Mock技術(shù) 4 Mock技術(shù)截取一段stackflow中的解釋:
Mock有以下幾個(gè)好處: 1、Mock可以用來(lái)解除測(cè)試對(duì)象對(duì)外部服務(wù)的依賴(比如數(shù)據(jù)庫(kù),第三方接口等),使得測(cè)試用例可以獨(dú)立運(yùn)行。不管是傳統(tǒng)的單體應(yīng)用,還是現(xiàn)在流行的微服務(wù),這點(diǎn)都特別重要,因?yàn)槿魏瓮獠恳蕾嚨拇嬖诙紩?huì)極大的限制測(cè)試用例的可遷移性和穩(wěn)定性。可遷移性是指,如果要在一個(gè)新的測(cè)試環(huán)境中運(yùn)行相同的測(cè)試用例,那么除了要保證測(cè)試對(duì)象自身能夠正常運(yùn)行,還要保證所有依賴的外部服務(wù)也能夠被正常調(diào)用。穩(wěn)定性是指,如果外部服務(wù)不可用,那么測(cè)試用例也可能會(huì)失敗。通過(guò)Mock去除外部依賴之后,不管是測(cè)試用例的可遷移性還是穩(wěn)定性,都能夠上一個(gè)臺(tái)階。 2、Mock的第二個(gè)好處是替換外部服務(wù)調(diào)用,提升測(cè)試用例的運(yùn)行速度。任何外部服務(wù)調(diào)用至少是跨進(jìn)程級(jí)別的消耗,甚至是跨系統(tǒng)、跨網(wǎng)絡(luò)的消耗,而Mock可以把消耗降低到進(jìn)程內(nèi)。比如原來(lái)一次秒級(jí)的網(wǎng)絡(luò)請(qǐng)求,通過(guò)Mock可以降至毫秒級(jí),整整3個(gè)數(shù)量級(jí)的差別 3、Mock的第三個(gè)好處是提升測(cè)試效率。這里說(shuō)的測(cè)試效率有兩層含義。第一層含義是單位時(shí)間運(yùn)行的測(cè)試用例數(shù),這是運(yùn)行速度提升帶來(lái)的直接好處。而第二層含義是一個(gè)測(cè)試人員單位時(shí)間創(chuàng)建的測(cè)試用例數(shù)。如何理解這第二層含義呢?以單體應(yīng)用為例,隨著業(yè)務(wù)復(fù)雜度的上升,為了運(yùn)行一個(gè)測(cè)試用例可能需要準(zhǔn)備很多測(cè)試數(shù)據(jù),與此同時(shí)還要盡量保證多個(gè)測(cè)試用例之間的測(cè)試數(shù)據(jù)互不干擾。為了做到這一點(diǎn),測(cè)試人員往往需要花費(fèi)大量的時(shí)間來(lái)維護(hù)一套可運(yùn)行的測(cè)試數(shù)據(jù)。有了Mock之后,由于去除了測(cè)試用例之間共享的數(shù)據(jù)庫(kù)依賴,測(cè)試人員就可以針對(duì)每一個(gè)或者每一組測(cè)試用例設(shè)計(jì)一套獨(dú)立的測(cè)試數(shù)據(jù),從而很容易的做到不同測(cè)試用例之間的數(shù)據(jù)隔離性。而對(duì)于微服務(wù),由于一個(gè)微服務(wù)可能級(jí)聯(lián)依賴很多其他的微服務(wù),運(yùn)行一個(gè)測(cè)試用例甚至需要跨系統(tǒng)準(zhǔn)備一套測(cè)試數(shù)據(jù),如果沒(méi)有Mock,基本上可以說(shuō)是不可能的。因此,不管是單體應(yīng)用還是微服務(wù),有了Mock之后,QE就可以省去大量的準(zhǔn)備測(cè)試數(shù)據(jù)的時(shí)間,專注于測(cè)試用例本身,自然也就提升了單人的測(cè)試效率。 5 相關(guān)的Mock工具5.1 Mockito、EasyMockEasyMock 以及 Mockito 都因?yàn)榭梢詷O大地簡(jiǎn)化單元測(cè)試的書(shū)寫(xiě)過(guò)程而被許多人應(yīng)用在自己的工作中,但是這兩種 Mock 工具都不可以實(shí)現(xiàn)對(duì)靜態(tài)函數(shù)、構(gòu)造函數(shù)、私有函數(shù)、Final 函數(shù)以及系統(tǒng)函數(shù)的模擬,但是這些方法往往是我們?cè)诖笮拖到y(tǒng)中需要的功能。 5.2 powermockPowerMock是一個(gè)擴(kuò)展了其它如EasyMock等mock框架的、功能更加強(qiáng)大的框架。PowerMock使用一個(gè)自定義類加載器和字節(jié)碼操作來(lái)模擬靜態(tài)方法,構(gòu)造函數(shù),final類和方法,私有方法,去除靜態(tài)初始化器等等。通過(guò)使用自定義的類加載器,簡(jiǎn)化采用的IDE或持續(xù)集成服務(wù)器不需要做任何改變。熟悉PowerMock支持的mock框架的開(kāi)發(fā)人員會(huì)發(fā)現(xiàn)PowerMock很容易使用,因?yàn)閷?duì)于靜態(tài)方法和構(gòu)造器來(lái)說(shuō),整個(gè)的期望API是一樣的。PowerMock旨在用少量的方法和注解擴(kuò)展現(xiàn)有的API來(lái)實(shí)現(xiàn)額外的功能。目前PowerMock支持EasyMock和Mockito。 5.3 mock底層原理①M(fèi)ockito底層使用了動(dòng)態(tài)代理,用到了CGLIB。因此需要被mock的對(duì)象,Mockito都會(huì)生成一個(gè)子類繼承該類,這也就是為什么final類、private方法、static方法不可以被Mock的原因 ②powermock的底層原理 我們首先看powermock的依賴 下面是PowerMock的簡(jiǎn)單實(shí)現(xiàn)原理:
6 powermock的使用這里吐血推薦一本電子書(shū) 7 springboot和powermock整合一定要注意powermock的版本號(hào),我在這里就踩了很多坑,血淋淋的教訓(xùn)啊,由于公司與springboot繼承用的是最新的powermock,截止2019年4月12日,powermock-module-junit4的Maven地址倉(cāng)庫(kù)最新版本是2.0.0 ,也正是powermock使用的太新了,導(dǎo)致后面遇到的問(wèn)題,百度google根本無(wú)法解決(因?yàn)樗麄兌歼€停留在1.x版本中),最后也是通過(guò)github官方文檔才最終解決的
7.1 重要注解
下面主要對(duì)上面幾個(gè)注解做相關(guān)解釋: @SpringBootTest:表明這是一個(gè)springboot測(cè)試類,會(huì)自動(dòng)加載springboot主啟動(dòng)程序 @RunWith(PowerMockRunner.class): 使用powermock自己的Runner @PowerMockRunnerDelegate(SpringRunner.class): 將powermock整合到spring容器中 @PowerMockIgnore({"javax. @PrepareForTest({HSSFWorkbook.class,HSSFCellStyle.class}): 這個(gè)注解是告訴PowerMock為我提前準(zhǔn)備一個(gè)xxx的class,根據(jù)我測(cè)試預(yù)期的行為去準(zhǔn)備 至此,springboot和powermock的整合就完成了! 7.2 PrepareForTest不能隨便加首先來(lái)看一段代碼:不使用@PrepareForTest
程序運(yùn)行成功! 使用@PrepareForTest
我們?cè)趖est()測(cè)試中完全沒(méi)有用到powermock,但是為什么會(huì)失敗呢? 原因:@PrepareForTest中的HSSFWorkbook.class,會(huì)告訴powermock提前準(zhǔn)備這個(gè)類文件,那么當(dāng)程序執(zhí)行的時(shí)候,需要的該類的時(shí)候,就會(huì)使用到powermock準(zhǔn)備的類 到目前為止,讀者可能會(huì)認(rèn)為 可以看到,這里new HSSFWorkbook()對(duì)象完全是一個(gè)正常的對(duì)象,而非powermock的對(duì)象,并且在該類中使用的也是這個(gè)真對(duì)象 直到運(yùn)行到MockGateway這個(gè)類 才出現(xiàn)問(wèn)題,在powermock中會(huì)有大量的代理類,攔截器,這些類中會(huì)使用到pokwermock的HSSFWorkbook的對(duì)象,而非真正的HSSFWorkbook對(duì)象,因此會(huì)出現(xiàn)問(wèn)題 7.3 不是所有的類都可以Powermock一個(gè)私有類是完全可以powermock的,那么是不是所有的類都可以powermock嗎? 答案是:否定的()
定位至HSSFCellStyle 133行 我們發(fā)現(xiàn)這是一個(gè)編譯期常量,跟ThreadLocal,是沒(méi)辦法跟powermock對(duì)象一起創(chuàng)建的 切記:powermock對(duì)象是無(wú)法改變編譯期常量的 7.4 @InjectMock @Mock區(qū)別
這里的@InjectMocks和@Autowired功能完完全全一樣,唯一不同的是,@InjectMocks可以使oneDependency這個(gè)Mock對(duì)象自動(dòng)注入到someHandler這個(gè)對(duì)象中。注意:①@InjectMocks所表示的對(duì)象及someHandler是一個(gè)普通的對(duì)象 ②Mock所表示的對(duì)象及oneDependency是一個(gè)Mock對(duì)象 7.5 @Mock和@MockBean的區(qū)別@MockBean 會(huì)被裝配到相關(guān)的類中 代替@Autowired @Mock 不會(huì)被裝配到相關(guān)的類中 無(wú)法代替@Autowired 7.6 Mock方法中的嵌套方法
即使Mock了changeAlarmLevel方法,其中的
還是會(huì)正常執(zhí)行的 7.7 mock對(duì)象中的參數(shù)不要再做運(yùn)算
mock的時(shí)候不能 Mockito.anyString(),Mockito.anyList() 而要 Mockito.any(),Mockito.anyList() 因?yàn)閙ock對(duì)象中的參數(shù)執(zhí)行了相關(guān)運(yùn)算 參考資料: https://zhidao.baidu.com/question/390585793246337165.html https://www.cnblogs.com/ysocean/p/6889906.html https://www.cnblogs.com/hunterCecil/p/5721468.html 請(qǐng)尊重作者勞動(dòng)成果,轉(zhuǎn)載請(qǐng)注明出處。以上內(nèi)容若有侵權(quán),請(qǐng)聯(lián)系作者,立即刪除。來(lái)源:http://www./content-4-162901.html |
|
來(lái)自: 印度阿三17 > 《開(kāi)發(fā)》