一.什麼是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的使用:
- MOCK通過參數傳遞的對象
需要測試的目標代碼 Public class ConvertController{ @Resource private ConvertServiceImpl convertservice; Public APIResult convert(HttpServletRequest request){ Return convertservice.getConvertResult(request.getInputStream(), request.getContentType()); } } 測試方法 使用註解時需加上: 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()); } |
- mock方法內部new出來的對象
目標代碼 Public class create{
} 測試代碼
|
- 靜態方法的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); |
備註:要加註解@PrepareForTest(Ioutils.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.assertSame(expected,actual):比較兩個參數是否相等,適用於八大基本數據類型
Assert.assertSame(Object expected,Object actual):比較兩個對象的地址是 否相等不能比較內容
Assert.assertTrue():如果爲true,則運行成功,反正運行失敗,並且無錯誤提示
Assert.assertSame(String message,Object[] expected,Object[] actual):比較兩個數組是否相等(數組長度和對應數組元素),若不相等則返回message
Assert.assertNotNull():斷言不爲空
Assert.assertNull():斷言爲空
- 驗證方法是否被調用:verify()
備註:
- verify是負責驗證的函數,接收的是mock的對象,不能接收實例對象
- 驗證不成功,直接報錯
- 使用verify()可及早發現自己的錯誤,預期的方法沒有調用,實際調用肯定出錯
- Verify()方法應該放在實際調用之後;
Mockito.verify(list).get(0);//驗證get(0)被調用 Mockito.verify(list,never()).get(0);//驗證get(0)沒有被調用 Mockito.verify(list,times(n)).get(0);//驗證get(0)被調用了n次 Mockito.verify(list,atLeast(n)).get(0);//驗證get(0)至少被調用了n次 |