回到官网: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复杂一点的功能。