日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Powermock2.0.0 詳細(xì) 總結(jié)

 印度阿三17 2019-04-13

目錄

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中的解釋:

Mocking isprimarily used in unit testing. An object under test may have dependencies onother (complex) objects. To isolate the behaviour of the object you want totest you replace the other objects by mocks that simulate the behavior of thereal objects. This is useful if the real objects are impractical to incorporateinto the unit test. 
MOCK主要被用于在單測(cè)中,某個(gè)對(duì)象在測(cè)試過(guò)程中有可能依賴于其他的復(fù)雜對(duì)象,通過(guò)mocks去模擬真實(shí)的其他對(duì)象(模塊)去代替你想要去測(cè)試的其他的對(duì)象(模塊),如果其他對(duì)象(模塊)是很難從單元測(cè)試中剝離開(kāi)來(lái)的話,這是非常有用的

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、EasyMock

EasyMock 以及 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 powermock

PowerMock是一個(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的依賴

可以看出來(lái),它有兩個(gè)重要的依賴:javassist和objenesis。
javassist是一個(gè)修改java字節(jié)碼的工具包,objenesis是一個(gè)繞過(guò)構(gòu)造方法來(lái)實(shí)例化一個(gè)對(duì)象的工具包。由此看來(lái),PowerMock的本質(zhì)是通過(guò)修改字節(jié)碼來(lái)實(shí)現(xiàn)對(duì)靜態(tài)和final等方法的mock的

下面是PowerMock的簡(jiǎn)單實(shí)現(xiàn)原理:

  • 當(dāng)某個(gè)測(cè)試方法被注解@PrepareForTest標(biāo)注以后,在運(yùn)行測(cè)試用例時(shí),會(huì)創(chuàng)建一個(gè)新的org.powermock.core.classloader.MockClassLoader實(shí)例,然后加載該測(cè)試用例使用到的類(系統(tǒng)類除外)。

  • PowerMock會(huì)根據(jù)你的mock要求,去修改寫(xiě)在注解@PrepareForTest里的class文件(當(dāng)前測(cè)試類會(huì)自動(dòng)加入注解中),以滿足特殊的mock需求。例如:去除final方法的final標(biāo)識(shí),在靜態(tài)方法的最前面加入自己的虛擬實(shí)現(xiàn)等。

  • 如果需要mock的是系統(tǒng)類的final方法和靜態(tài)方法,PowerMock不會(huì)直接修改系統(tǒng)類的class文件,而是修改調(diào)用系統(tǒng)類的class文件,以滿足mock需求。

6 powermock的使用

這里吐血推薦一本電子書(shū)
網(wǎng)盤(pán)鏈接: https://pan.baidu.com/s/1ZndwumRgSTqmtn__RNVosA 密碼:e8w4

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官方文檔才最終解決的

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>2.0.0</version>
    <scope>test</scope>
    </dependency>
    <dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito</artifactId>
    <version>2.0.0</version>
<scope>test</scope>
</dependency>

7.1 重要注解

@SpringBootTest  // 表明這是一個(gè)springboot測(cè)試類,會(huì)自動(dòng)加載springboot主啟動(dòng)程序
@RunWith(PowerMockRunner.class) //使用powermock自己的Runner
@PowerMockRunnerDelegate(SpringRunner.class) //將powermock整合到spring容器中
@PowerMockIgnore({"javax.*.*", "com.sun.*", "org.xml.*", "org.apache.*"})
@PrepareForTest({HSSFWorkbook.class,HSSFCellStyle.class})
public class Demo {

    @Test
    public void test() throws Exception {
        EmployeeService service = PowerMockito.mock(EmployeeService.class);
        PowerMockito.when(service.hello()).thenReturn(999);
        int result = service.hello();
        Assert.assertEquals(999, result);
    }

}

下面主要對(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.*.*", "com.sun.", "org.xml.", "org.apache.*"}) : 這個(gè)注解很重要,這也是powermock2.0.0與1.x版本重大不一樣的地方,因?yàn)閜owermock自帶一個(gè)類加載器,使用該注解來(lái)禁止powermock類加載器加載一些類,避免和JVM類加載器沖突

@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

@SpringBootTest
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PowerMockIgnore({"javax.*.*", "com.sun.*", "org.xml.*", "org.apache.*"})
// @PrepareForTest({HSSFWorkbook.class,HSSFCellStyle.class}) 不使用該注解
public class Demo {
    @Test 
    public void test() throws Exception{
        HSSFWorkbook wb = new HSSFWorkbook();
        wb.createSheet();
    }
}

程序運(yùn)行成功!

使用@PrepareForTest

@SpringBootTest
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PowerMockIgnore({"javax.*.*", "com.sun.*", "org.xml.*", "org.apache.*"})
@PrepareForTest({HSSFWorkbook.class}) 
public class Demo {
    @Test 
    public void test() throws Exception{
        HSSFWorkbook wb = new HSSFWorkbook();
        wb.createSheet();
    }
}

我們?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)為 HSSFWorkbook wb = new HSSFWorkbook();將會(huì)創(chuàng)建powermock準(zhǔn)備的HSSFWorkbook對(duì)象,那么我debug程序,一探究竟

可以看到,這里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嗎?

答案是:否定的()

@SpringBootTest
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PowerMockIgnore({"javax.*.*", "com.sun.*", "org.xml.*", "org.apache.*"})
@PrepareForTest({HSSFWorkbook.class})
public class Demo {
    
    @Test
    public void test3() throws Exception{
        PowerMockito.mock(HSSFCellStyle.class);
    }
    
}

定位至HSSFCellStyle 133行

我們發(fā)現(xiàn)這是一個(gè)編譯期常量,跟ThreadLocal,是沒(méi)辦法跟powermock對(duì)象一起創(chuàng)建的

切記:powermock對(duì)象是無(wú)法改變編譯期常量的

7.4 @InjectMock @Mock區(qū)別

    @InjectMocks
    private SomeHandler someHandler;
 
    @Mock 或者 @Spy
    private OneDependency oneDependency; // 此mock將被注入到someHandler

這里的@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方法中的嵌套方法

Mockito.when(alarmRulesDao.changeAlarmLevel(Mockito.anyInt(),Mockito.anyInt()))
                .thenReturn(-1);

Integer changeNumber = alarmRulesDao.changeAlarmLevel(changeAlarmlevelRequest.getId(), changeAlarmlevelRequest.getAlarmLevel());

即使Mock了changeAlarmLevel方法,其中的

changeAlarmlevelRequest.getId()
changeAlarmlevelRequest.getAlarmLevel()

還是會(huì)正常執(zhí)行的

7.7 mock對(duì)象中的參數(shù)不要再做運(yùn)算

this.getHSSFWorkbook(downloadVO.getSheetName(), downloadList));

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

http://www./post/355904

https://www.cnblogs.com/hunterCecil/p/5721468.html

https://qicen./blog/1928257

請(qǐng)尊重作者勞動(dòng)成果,轉(zhuǎn)載請(qǐng)注明出處。以上內(nèi)容若有侵權(quán),請(qǐng)聯(lián)系作者,立即刪除。來(lái)源:http://www./content-4-162901.html

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多