爲了方便在類中使用,可以使用java 的靜態引入,將mockito中常用的方法引入到單元測試類中。
Import static org.mockito.Mockito.*;
創建Mock對象
這裏將會使用List作爲測試的對象,主要原因是這個類比較常用,大家對接口也都比較熟悉。
在mockito中要mock一個對象很簡單,只需要調用mock(Class)方法即可。
List mockedStringList = mock(List.class);#mock object creation
除了調用mock(Class)創建mock對象,Mockito還提供使用annotation方式進行創建mock對象。對於使用annotation創建對象的方法會在以後的筆記中集中進行講解,這裏主要討論mock對象以及基本使用。
使用Mock對象進行behavior verification
對mock對象進行行爲檢測,也就是查看mock對象的某些特定方法是否被使用了,以及被使用了幾次。在mockito中,通過verify(T)方法來進行behavior verification。這個方法會返回T對象本身,需要緊接了調用某個特定的方法來判斷這個特定的方法是否得到了調用。
@Test public void behaviorVerification() { List<String> mockedStringList = mock(List.class);//mock object creation mockedStringList.add("robin hood");//invoke add function of list verify(mockedStringList).add("robin hood");//verify the add function is called once }
一般來說,在單元測試中基本不會手動調用一個方法(如例子中的MockedStringList.add(“robin hood”)),然後再驗證這個方法被調用過。一般來說,是一個對象B存在於另外一個對象A中,當調用A對象的某個方法,如A.run(),而A.run()中又調用了B對象的B.go()方法,那麼在單元測試的時候,就可以創建一個B的mock對象,並讓A使用這個mock對象,然後通過調用A的方法來檢測B的某個方法是否被調用了。如下面的例子,Printer.print()方法內部調用了document.getWholeFormattedContent()方法,因此可以通過檢測在調用Printer.print()方法的時候document.getWholeFormattedContent()方法是否被調用過來判斷Printer.print()的邏輯是否正確。
public static class Printer { public void print(Document document) { String documentContent = document.getWholeFormattedContent(); } } public static class Document { public String getWholeFormattedContent() { return ""; } } @Test public void behaviorVerificationInside() { Document document = mock(Document.class); Printer printer = new Printer(); printer.print(document); verify(document).getWholeFormattedContent(); }
verify(T)方法僅僅是進行了簡單的判斷,判斷某個特定的方法(這個例子中是document.getWholeFormattedContent()方法)只被調用了一次。verify(T)其實是verify(T, times(1))的縮略形式。
使用Mock對象進行state verification
有些時候,在做單元測試的時候,不僅僅關心某個方法被運行了,還關心這個方法的返回值對最後結果的影響,這個時候就需要mock對象的另外一個功能了——stub。如果大家對這個概念還不是很清楚的話,可以查看下Mocktio讀書筆記的第一講,裏面介紹了stub和mock的區別。
在mockito中,通過調用when(T methodCall).thenReturn(T expectedResult)來插入預定值。這個方法聲明瞭,當methodCall被調用的時候(包含特定的參數),expectedResult會被返回,不管method內部邏輯如何。
@Test public void run() { List<String> list = mock(ArrayList.class); when(list.size()).thenReturn(5);// when list.size() is called, 5 will returned, although // there is no data in the real list. Assert.assertEquals(5, list.size());// will pass the assertion }
在上面的這個例子中,一開始mock了一個list對象,並沒有往裏面添加任何數據,但是通過when().thenReturn()方法,設置了一個返回值5給了list.size()方法,那麼當這個mock的list對象的size()方法真的被調用的時候,數值5就會返回。這就是完成了對mock對象的插值。當然,在實際應用中一樣爲一個方法設置了插值,然後在手動調用這個方法,一般是爲某個mock的對象方法進行插值,然後在調用其它對象方法的時候會在內部調用到mock的對象方法,這時mock對象的方法就會返回預設好的值。如下面的例子,mock了一個list,在實際操作中,並沒有往list添加任何數據,只是指定了當list.indexOf(“abc”)方法被調用的時候返回數值1。然後驗證container.isThere(“abc”)方法返回true,因爲container.isThere()方法內部是調用了list.indexOf()來進行判斷是否該元素存在的。
public static class ListContainer{ final List<String> list; public ListContainer(List<String> list) { this.list = list; } public boolean isThere(String text) { return list.indexOf(text)>=0; } } @Test public void runInside() { List<String> list = mock(ArrayList.class); ListContainer container = new ListContainer(list); when(list.indexOf("abc")).thenReturn(1); Assert.assertTrue(container.isThere("abc")); }
同步更新到WordPress