回到官網:http://mockito.org/,打開documentation能夠看到原文。 ide
強烈建議不熟悉Mockito的同窗先看看我寫的Mockito(一)入門篇和(二)實例篇以後再來看這篇文章。 ui
由於只有看了前兩篇文章才明白mockito的本質以及該如何使用它。 spa
下面是按原文 翻譯+註釋 的對Mockito所有功能的介紹。 .net
1, 使用mockito驗證行爲。 翻譯
//首先要importMockito. debug
import static org.mockito.Mockito.*; 對象
//mock creation element
List mockedList = mock(List.class); rem
//using mock object get
mockedList.add("one");
mockedList.clear();
//驗證add方法是否在前面被調用了一次,且參數爲「one」。clear方法一樣。
verify(mockedList).add("one");
verify(mockedList).clear();
//下面的驗證會失敗。由於沒有調用過add("two")。
verify(mockedList).add("two");
原文中的一句話很重要:Once created, mock will remember all interactions.因此mockito知道前面是否調用過某方法。
2, 使方法調用返回指望的值。也被稱爲stubbing
//You can mock concrete classes, not only interfaces
LinkedList mockedList = mock(LinkedList.class);
//stubbing。當get(0)被調用時,返回"first". 方法get(1)被調用時,拋異常。
when(mockedList.get(0)).thenReturn("first");
when(mockedList.get(1)).thenThrow(new RuntimeException());
//following prints "first"
System.out.println(mockedList.get(0));
//following throws runtime exception
System.out.println(mockedList.get(1));
//following prints "null" because get(999) was not stubbed
System.out.println(mockedList.get(999));
默認狀況下,對於全部有返回值且沒有stub過的方法,mockito會返回相應的默認值。
對於內置類型會返回默認值,如int會返回0,布爾值返回false。對於其餘type會返回null。
這裏一個重要概念就是: mock對象會覆蓋整個被mock的對象,所以沒有stub的方法只能返回默認值。
//重複stub兩次,則以第二次爲準。以下將返回"second":
when(mockedList.get(0)).thenReturn("first");
when(mockedList.get(0)).thenReturn("second");
//若是是下面這種形式,則表示第一次調用時返回「first」,第二次調用時返回「second」。能夠寫n多個。
when(mockedList.get(0)).thenReturn("first").thenReturn("second");
可是,若是實際調用的次數超過了stub過的次數,則會一直返回最後一次stub的值。
如上例,第三次調用get(0)時,則會返回"second".
3, 參數匹配
在上例中若是想實現get(任意整數)時,都返回「element」時,該怎麼作呢?很簡單。
//stubbing 使用了內置的anyint() matcher.
when(mockedList.get(anyInt())).thenReturn("element");
//所以除了anyint()以外,還有其餘不少matcher。這裏請參考原文。
//使用了matcher同樣能夠驗證被調用的次數。
verify(mockedList).get(anyInt());
這裏有一個限制就是,若是在調用方法時須要傳入多個參數,其中一個參數使用了argument matcher,那麼全部的參數必須都是matcher。
不能夠matcher和實際的參數混着用。
這裏也可使用custom argument matcher。由於不少時候輸入參數不是build-in 類型,而是咱們本身寫的一些類,或特殊對象。
這時要使用argument matcher,就必須訂製特殊的matcher了。
下例是一個特殊的matcher的實例,這個matcher能夠匹配任何file對象。
public class SayHiTest {
@Test
public void testSayHi() throws Exception {
File mock = mock(File.class); //首先mock File類。
//注意new IsAnyFiles()並非一個matcher,須要調用argThat(new IsAnyFiles()))才返回一個matcher。
//下句中stub:當調用renameTo方法時,返回false。該方法參數能夠是任意file對象。
when(mock.renameTo(argThat(new IsAnyFiles()))).thenReturn(false);
mock.renameTo(new File("test"));
//下句verify renameTo方法被調用了一次,同時輸入參數是任意file。
verify(mock).renameTo(argThat(new IsAnyFiles()));
}
}
class IsAnyFiles extends ArgumentMatcher<File> {
public boolean matches(Object file) {
return file.getClass() == File.class;
}
}
另一個參數匹配的例子:
class IsSOAPMessage extends ArgumentMatcher<SOAPMessage> {
public boolean matches(Object soapMessage) {
return (soapMessage instanceof SOAPMessage) || soapMessage==null;
}
}
//上面的macther不只能夠匹配任意的SOAPMessage對象,若是輸入參數爲空也能夠匹配上。這裏說一下我犯過的一個錯誤。
我在作參數匹配的時候,沒有考慮到輸入參數爲空的狀況,致使matcher匹配不上,進而stub的行爲沒法生效。
其實在發現mock對象沒有想本身想象的方式工做時,最好的方法就是debug進去,首先要先肯定mock對象是否是真的傳遞進去了。而後再一步步的debug。
一般遇到的兩種狀況就是1,mock對象沒有傳遞進去。2,參數沒有匹配上。
4, 驗證方法被調用了特定次數/至少x次/最多x次/從未被調用
//是否add("twice")被調用了兩次。
verify(mockedList, times(2)).add("twice");
//驗證add("twice")被調用了至少一次。以及其餘。
verify(mockedList, atLeastOnce()).add("twice");
verify(mockedList, atLeast(2)).add("twice");
verify(mockedList, atMost(5)).add("twice");
verify(mockedList, never()).add("twice");
5, 調用方法時拋出異常
doThrow(new RuntimeException()).when(mockedList).clear();
後面還會再介紹幾個相似的方法,例如doReturn()。
6, 驗證順序
//下面的代碼驗證firstMock先被調用,secondMock後被調用。
inOrder.verify(firstMock).add("was called first");
inOrder.verify(secondMock).add("was called second");
7, 驗證mock之間沒有相互做用6,7都不是很明白實際意義是什麼。
8, 找到冗餘的調用
用never()就能夠實現,很少說
9, 使用@mock 定義mock。
以前都是使用mock()來模擬一個對象。用@mock是一個shorthand。
public class ArticleManagerTest {
@Mock private ArticleCalculator calculator;
@Mock private ArticleDatabase database;
@Mock private UserProvider userProvider;
private ArticleManager manager;
以後再繼續介紹mockito複雜一點的功能。