赞
踩
repositories { jcenter() }
dependencies { testCompile "org.mockito:mockito-core:1.+" }
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.10.19</version>
</dependency>
二、使用
详情请参考:http://mockito.org/
1、验证某些行为:
//静态导入会使代码更简洁
import static org.mockito.Mockito.*;
//创建Mock对象
List mockedList = mock(List.class);
//使用 Mock对象
mockedList.add("one");
mockedList.clear();
//验证
verify(mockedList).add("one");
verify(mockedList).clear();
其中 verify 方法 还有2个参数的方法:第二个参数可以传入 times(x),atLeastOne() 、never()、atMost(x)等,这些参数表示验证方法执行的次数。
如:
{
// 验证方法被调用次数
LinkedList mockedList = mock(LinkedList.class);
mockedList.add("one");
mockedList.add("two");
mockedList.add("two");
mockedList.add("three");
mockedList.add("three");
mockedList.add("three");
//验证 add("one")执行了1次
verify(mockedList,times(2)).add("two");
//验证 add("two")执行了2次
verify(mockedList,times(3)).add("three");
//验证 add("never")执行了3次
verify(mockedList,never()).add("never");
//验证 add("one")最少执行了1次
verify(mockedList,atLeast(1)).add("one");
//验证 add("three")最多执行了10次
verify(mockedList,atMost(10)).add("three");
}
如果第二个参数不写,相当于执行了 verify(mockedList,times(1))。
2、如何测试一些桩
//你可以mock具体的类型,不仅只是接口
LinkedList mockedList = mock(LinkedList.class);
//测试桩,在调用mockedList.get(0)时会返回 "first"
when(mockedList.get(0)).thenReturn("first");
//测试桩,在调用mockedList.get(1)时 会抛出RuntimeException异常
when(mockedList.get(1)).thenThrow(new RuntimeException());
//会打印出 "first"
System.out.println(mockedList.get(0));
//会抛出runtime exception
System.out.println(mockedList.get(1));
//mockedList.get(999)没有打桩 ,所以会打印出 "null"
System.out.println(mockedList.get(999));
3、参数匹配器
//使用内置的anyInt()参数匹配器,当调用get(整数值)时,都返回"element"
when(mockedList.get(anyInt())).thenReturn("element");
//使用自定义的参数匹配器,(在 isValid()函数中返回你自己的匹配器实现)
when(mockedList.contains(argThat(isValid()))).thenReturn("element");
//打印 "element"
System.out.println(mockedList.get(999));
// 你也可以验证参数匹配器
verify(mockedList).get(anyInt());
有一点需要注意,如果使用参数匹配器,那么所有的参数都因该有匹配器提供。
例如:
//这个是正确的,因为 eq()也是一个参数匹配器
verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));
//下面的代码是错误的,因为所有参数必须由匹配器提供,二参数"third argument"并非由参数//匹配器提供
verify(mock).someMethod(anyInt(), anyString(), "third argument");
4、验证函数的执行次数
//using mock
mockedList.add("once");
mockedList.add("twice");
mockedList.add("twice");
mockedList.add("three times");
mockedList.add("three times");
mockedList.add("three times");
//following two verifications work exactly the same - times(1) is used by default
verify(mockedList).add("once");
verify(mockedList, times(1)).add("once");
//exact number of invocations verification
verify(mockedList, times(2)).add("twice");
verify(mockedList, times(3)).add("three times");
//verification using never(). never() is an alias to times(0)
verify(mockedList, never()).add("never happened");
//verification using atLeast()/atMost()
verify(mockedList, atLeastOnce()).add("three times");
verify(mockedList, atLeast(2)).add("five times");
verify(mockedList, atMost(5)).add("three times");
这些方法在将第一条的时候,已经提过了,这里就不在说明了。
5、为无返回值对象打桩抛出异常
//当调用mockedList.clear()时,将抛出RuntimeException 异常
doThrow(new RuntimeException()).when(mockedList).clear();
//将抛出RuntimeException:
mockedList.clear();
6、验证方法调用顺序:
// A.当只有一个mock对象时
List singleMock = mock(List.class);
//使用单个mock对象
singleMock.add("was added first");
singleMock.add("was added second");
//创建一个InOrder
InOrder inOrder = Mockito.inOrder(singleMock);
//确保add("was added first") 在add("was added second")之前
inOrder.verify(singleMock).add("was added first");
inOrder.verify(singleMock).add("was added second");
// B. 多个Mock对象时
List firstMock = mock(List.class);
List secondMock = mock(List.class);
//使用mock对象那个
firstMock.add("was called first");
secondMock.add("was called second");
//create inOrder object passing any mocks that need to be verified in order
InOrder inOrder = Mockito.inOrder(firstMock, secondMock);
//确保firstMock.add("was called firs") 在 secondMock.add("was called second")之前
inOrder.verify(firstMock).add("was called first");
inOrder.verify(secondMock).add("was called second");
7、确保交互操作没有执行在Mock对象上
List mockOne = mock(List.class);
//使用Mock对新娘
mockOne.add("one");
//普通验证
verify(mockOne).add("one");
//验证 add("two") 没有执行过
verify(mockOne, never()).add("two");
List mockTwo = mock(List.class);
List mockThree = mock(List.class);
//验证mockTwo和mockThree 没有交互过
verifyZeroInteractions(mockTwo, mockThree);
8、寻找多余的调用:
List mockedList = mock(List.class);
//常见mock对象
mockedList.add("one");
mockedList.add("two");
//这里只验证了 add("one")没有验证add("two"),这将导致 //verifyNoMoreInteractions(mockedList);验证失败
verify(mockedList).add("one");
//这里将验证失败
verifyNoMoreInteractions(mockedList);
9,简化Mock对象的创建
使用@Mock注解,它的好处在于:
1、最小化重复地创建代码
2、是测试类的代码可读性更高
3、是验证错误更易于阅读,因为字段名可以表示Mock对象
public class ArticleManagerTest {
@Mock private ArticleCalculator calculator;
@Mock private ArticleDatabase database;
@Mock private UserProvider userProvider;
private ArticleManager manager;
注意,必须在调用 MockitoAnnotations.initMocks(testClass); 进行初始化。
例如可以在基类,或者当前类
public class ArticleManagerTest extends SampleBaseTestCase {
@Mock private ArticleCalculator calculator;
@Mock private ArticleDatabase database;
@Mock private UserProvider userProvider;
private ArticleManager manager;
@Before public void setup() {
manager = new ArticleManager(userProvider, database, calculator);
}
}
public class SampleBaseTestCase {
@Before public void initMocks() {
MockitoAnnotations.initMocks(this);
}
}
10、为连续调用做测试桩
when(mock.someMethod("some arg"))
.thenThrow(new RuntimeException())
.thenReturn("foo");
//第一次调用时: 抛出RuntimeException异常
mock.someMethod("some arg");
//第二次调用时,打印 "foo"
System.out.println(mock.someMethod("some arg"));
//后续的调用也是 输出"foo"
System.out.println(mock.someMethod("some arg"));
还有一种简短版本:
when(mock.someMethod("some arg"))
.thenReturn("one", "two", "three");
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。