Mock:PowerMockito,EasyMock,Mockito

一.什麼是MOCK?

  模擬真實對象行爲的一個假的對象,該對象中的數據可以按照自己的期望賦予。

二.爲什麼要MOCK?

1.在單體測試過程中,有的對象很難構造或者獲取;

2.調用的別人的邏輯還沒有實現。

三.PowerMockito,EasyMock,Mockito的區別:

EasyMock:EasyMock 使用動態代理,能夠創建任何接口的基本實現,可以驗證方法的調用種類、次數、順序,可以令 Mock 對象返回指定的值或拋出指定異常。

使用步驟:

第一步:使用 EasyMock 生成 Mock 對象;

第二步:錄製 Mock 對象的預期行爲和輸出;

第三步:將 Mock 對象切換到 播放 狀態;

第四步:調用 Mock 對象方法進行單元測試;

第五步:對 Mock 對象的行爲進行驗證。

Mockito:可校驗哪些函數被調用,消除了對期望行爲的需要

使用步驟:

第一步:使用 mockito 生成 Mock 對象;

第二步:定義(並非錄製) Mock 對象的行爲和輸出(expectations部分);

第三步:調用 Mock 對象方法進行單元測試;

第四步:對 Mock 對象的行爲進行驗證。

PowerMock:是在EasyMock 以及 Mockito上的擴展,可以實現對靜態函數、構造函數、私有函數、Final 函數以及系統函數的模擬

四.PowerMock的常用註解:

@RunWith(PowerMockRunner.class)

@PrepareForTest({YourClass.class})//模擬靜態,final,私有方法等時需加上

備註:以上兩個備註一般同時使用

@InjectMocks:mock將要注入的實例

@Mock:創建一個mock,該mock對象所有方法被置空

@Spy:創建一個mock,該mock對象所有方法都是真實的

五.PowerMockito的使用:

  1. MOCK通過參數傳遞的對象

需要測試的目標代碼

Public class ConvertController{

@Resource

    private ConvertServiceImpl convertservice;

    Public APIResult convert(HttpServletRequest request){

          Return convertservice.getConvertResult(request.getInputStream(),

request.getContentType());

}

}

測試方法

使用註解時需加上:
     @Before//在執行所有@Test之前執行

    public void setUp() throws Exception {

           controller = new ConvertController();//實例對象

           convertservice = Mockito.mock(ConvertServiceImpl.class); // 創建Mock對象

           Whitebox.setInternalState(controller, "convertservice", convertservice); // 注入依賴對象

  }

@Test

    public void testconvert() throws Exception {

        APIResult api = new APIResult(0, "error");

//mock一個HttpServletRequest對象

        HttpServletRequest request=PowerMockito.mock(HttpServletRequest.class);

        //調用convertservice.getConvertResult(args1,args2)時返回的預期結果api

         Mockito.when(convertservice.getConvertResult(request.getInputStream()

request.getContentType())).thenReturn(api);

         //調用實際的業務代碼,得出運行結果

        APIResult result = controller.convert(request);

         //預期結果和實際結果進行比較

        Assert.assertEquals(result.getCode(),api.getCode());

        Assert.assertEquals(result.getErrMsg(),api.getErrMsg());

   }

 

  1. mock方法內部new出來的對象

目標代碼

Public class create{

public boolean callInternalInstance(String path) { 

File file = new File(path); 

Return file.exits();

}

}

測試代碼

@RunWith(PowerMockRunner.class) 

Public class createtest{

@PrepareForTest(Create.class)@Test

Public void test callInternalInstance(){

File file = PowerMockito.mock(File.class); 

PowerMockito.whenNew(File.class).withArguments("bbb").thenReturn(file); 

PowerMockito.when(file.exists()).thenReturn(true); 

}

}

  1. 靜態方法的mock:

測試目標代碼:Ioutils的靜態方法toByteArray(inputsytream)

Byte[] by=Ioutils.toByteArray(inputsytream);

測試用例代碼:

    Byte[] bytes=new byte[]{1,2,3};

PowerMockito.mockStatic(IOUtils.class);

PowerMockito.when(IOUtils.toByteArray(any(InputStream.class))).thenReturn(bytes);

 

備註:要加註解@PrepareForTestIoutils.Class

六.@Spy和@Mock的區別

1.對於@Mock註釋的類的一般用法:

When(file.exits()).thenReturn(true);//exits()方法會執行一次,然後返回希望的結果true

2.對於@Spy註釋的類的一般用法:

doReturn(true).when(file).exits();//exits()方法不會執行,直接返回預期結果true

3.說明:

1>.使用@Mock生成的類,所有方法都不是真實的方法,而且返回值都是NULL。

2>.使用@Spy生成的類,所有方法都是真實方法,返回值都是和真實方法一樣的,並且@spy修飾的對象都必須先手動new出來,。

@spy的用法

List list=new LinkedList();

List spy=spy(list);

要調用mock的值:

Mockito.When(spy.size()).thenReturn(100);//打樁

System.out.println(spy.size());//100

調用實際的值:

System.out.println(spy.size());//0

 

 

4.使用場景:

1>.當對象的大部分方法實際調用,只有一小部分需要返回我們預期的值時使用@spy;

2>當某個對象的大部分或者全部方法都需要返回我們希望的值時使用@Mock

七.參數匹配問題

在mock一個方法時,對於方法的參數要求是很嚴格的,只有要執行的方法的參數與mock的方法中的參數相匹配時,mock方法才起作用,(這裏很容易導致空指針異常)

PowerMock提供提供了精確匹配和模糊匹配的方式:

 

1.精確匹配:

常用於String,int,boolean,long,double等可以直接構造的參數類型

Public class Usertest{

   @Test

   Public void testgetBookType(){

      Book book=PowerMockito.mock(Book.class);

      When(book.getType(Mockito.eq(“Jane Eyre”))).thenReturn(“novel”);

     //執行該方法並且參數爲“Jane Eyre”時返回“novel”

}

}

 

 

2.模糊匹配:

 

Public class Usertest{

   @Test

   Public void testgetBookType(){

      Book book=PowerMockito.mock(Book.class);

      When(book.getType(Mockito.startwith(Jane))).thenReturn(“Jane Eyre”);

      //參數以“Jane”開始的方法都返回“Jane Eyre”

}

}

 

3.任意匹配(可以解決大部分問題):

 

   無論入參是什麼值,都認爲是匹配的,常用的有:anyString,anyInt,anyLong等any(Class<T> clazz):不容易構造的類型可以用這種方式,如:any(InputStream.class)

     @Test

    public void testgetConvertResult1() throws Exception {

        // 測試文件上傳方式

        contentType = "multipart/form-data";

        APIResult result = convert.getConvertResult(any(InputStream.class), contentType);

        Assert.assertEquals(result.toString(), "{\"code\":400}");

}

 

可能需要手動導包:

import static org.mockito.Matchers.*;

八.單體測試常用的斷言:

Assert.assertSameexpected,actual:比較兩個參數是否相等,適用於八大基本數據類型

Assert.assertSame(Object expected,Object actual):比較兩個對象的地址是  否相等不能比較內容

Assert.assertTrue():如果爲true,則運行成功,反正運行失敗,並且無錯誤提示

Assert.assertSameString message,Object[] expected,Object[] actual:比較兩個數組是否相等(數組長度和對應數組元素),若不相等則返回message

Assert.assertNotNull():斷言不爲空

Assert.assertNull():斷言爲空

 

  • 驗證方法是否被調用:verify()

備註:

  1. verify是負責驗證的函數,接收的是mock的對象,不能接收實例對象
  2. 驗證不成功,直接報錯
  3. 使用verify()可及早發現自己的錯誤,預期的方法沒有調用,實際調用肯定出錯
  4. Verify()方法應該放在實際調用之後;

Mockito.verify(list).get(0);//驗證get(0)被調用

Mockito.verify(listnever()).get(0);//驗證get(0)沒有被調用

Mockito.verify(listtimes(n)).get(0);//驗證get(0)被調用了n

Mockito.verify(listatLeast(n)).get(0);//驗證get(0)至少被調用了n

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章