Mockito 简单语法使用
使用类库需要在build.gradle中加入mockito依赖配置:
testCompile 'org.mockito:mockito-core:2.8.9'
Mock的概念:
所谓的mock就是创建一个类的虚假的对象,在测试环境中,用来替换掉真实的对象,以达到两大目的:
1.验证这个对象的某些方法的调用情况,调用了多少次,参数是什么等等
2.指定这个对象的某些方法的行为,返回特定的值,或者是执行特定的动作
上面说了Mock的概念,下面开始搬砖,写段代码示例来说明Mockito的一些常用语法使用,代码如下:
/************************************************************
* Author: ssc
* Date: 2018/7/20
* Version: 1.0
* Description: 人的逻辑判断层
* History:
* <author> <time> <version > <desc>
***********************************************************/
public class Person {
/**
* 获取该类型性别并进行打印
*
* @param type 0代表女生、1代表男生、其他数字提示参数有误
*/
public void getSex(int type) {
if (type == 0) {
printing("女");
} else if (type == 1) {
printing("男");
} else {
printing("参数有误");
}
}
/**
* 打印方法
*
* @param content
*/
public void printing(String content) {
//这里为了简单我们直接控制台输出
System.out.print(content);
}
/**
* 判断类型是否是男人
*
* @param type
* @return
*/
public boolean isMan(int type) {
//处理逻辑这里为了方便我们直接进行简单判断
return type == 1;
}
}
1.如何mock出一个虚假的对象:
Person person = Mockito.mock(Person.class);
2. 如何验证方法调没调用
Mockito.verify(person).getSex(...);这句话的作用是,验证person的getSex得到了调用,调用次数为1次。因为这行代码其实是:Mockito.verify(person , Mockito.times(1)).getSex(...)的简写,或者说重载方法,注意其中的Mockito.times(1)。因此,如果你想验证一个对象的某个方法得到了多次调用,只需要将次数传给Mockito.times()就好了。
Mockito.verify(person, Mockito.times(3)).getSex(...); //验证person的方法getSex(...)得到了三次调用。
2.1验证方法的调用次数方法有:
- times(n):方法被调用n次
- never():没有被调用
- atLeast(n):至少被调用n次
- atLeastOnce():至少被调用1次,相当于atLeast(1)
- atMost():最多被调用n次
代码演示:
//执行1次
verify(person , times(1)).add(...);
//执行2次
verify(person , times(2)).add(...);
verify(person , times(3)).add(...);
//从不执行, never()等同于times(0)
verify(person , never()).add(...);
//验证至少执行1次
verify(person , atLeastOnce()).add(...);
//验证至少执行2次
verify(person , atLeast(2)).add(...);
//验证最多执行4次
verify(person , atMost(4)).add(...);
3. 在不关心参数为什么值的情况下,如何通过Mock的语法给出方法所需要的参数对应类型
比如上面的例子,我们在调用性别后,会走打印方法,这是我们只关心打印方法走没走,而不关心他的参数是什么的时候,我们就要用到Mock的any方法。代码如下:
Mockito.verify(person).printing(Mockito.anyString());
anyString()表示任何一个字符串都可以。下面我列举一些常用的参数适配方法
3.1参数适配方法
- anyString
- anyInt
- anyLong
- anyDouble
- anyObject 表示任何对象
- any(clazz)表示任何属于clazz的对象
- anyCollection
- anyCollectionOf(clazz)
- anyList(Map, set)
- anyListOf(clazz)等等
4. 指定某个方法的返回值,或者是执行特定的动作。
4.1指定某个方法的返回值
Mockito.when(mockObject.targetMethod(args)).thenReturn(desiredReturnValue);
该方法是执行mockObject.targetMethod()使其返回特定的值desiredReturnValue,据需用我们的person来举例:
//当调用person的isMan方法,同时传入"0"时,返回true
(注意这个时候我们调用person.isMan(0);的时候值为true而调用其他数字则为false,
如果我们忽略数字,传任何值都返回true时,就可以用到我们上面讲的any()参数适配方法)
Mockito.when(person.isMan(0)).thenReturn(true);
//当调用person的isMan方法,同时传入"0"时,返回false(注意同上面解释一样)
Mockito.when(person.isMan(0)).thenReturn(false);
相关语法
- doThrow(Throwable...):进行异常测试
@Test
public void testMock() {
List list = mock(List.class);
list.add("123");
//当list调用clear()方法时会抛出异常
doThrow(new RuntimeException()).when(list).clear();
list.clear();
}
- doReturn():指定返回值
@Test
public void testMock() {
List list = mock(List.class);
doReturn("123").when(list).get(anyInt());
System.out.println(list.get(0));
}
- doNothing() :指定void方法什么都不做
- doCallRealMethod():指定方法调用内部的真实逻辑
class Foo {
public void doFoo() {
System.out.println("method doFoo called.");
}
public int getCount() {
return 1;
}
}
@Test
public void testMock() {
Foo foo = mock(Foo.class);
//什么信息也不会打印, mock对象并不会调用真实逻辑
foo.doFoo();
//啥也不会打印出来
doNothing().when(foo).doFoo();
foo.doFoo();
doCallRealMethod().when(foo).doFoo();
//这里会调用真实逻辑, 打印出"method doFoo called."信息
foo.doFoo();
//这里会打印出0
System.out.println(foo.getCount());
doCallRealMethod().when(foo).getCount();
//这里会打印出"1"
System.out.println(foo.getCount());
}
4.2执行特定的动作
在安装中经常用到网络请求数据,而我们在测试时忽略网络请求这块时,就可以用到mock的执行特定的动作:
Mockito.doAnswer(desiredAnswer).when(mockObject).targetMethod(args);
传给doAnswer()的是一个Answer对象,我们想要执行什么样的动作,就在这里面实现。如:
//登录操作:
/**
* 网络请求返回
*/
public interface NetCallback {
void onSuccess(Object data);
void onFailure(int code, String msg);
}
/**
* 网络请求
* Created by xiaochuang on 4/25/16.
*/
public class Api{
public void get(String url, Map<String, String> params, NetworkCallback callback) {
//网络请求处理操作逻辑,这块忽略写法
//成功调用callback.onSuccess(data);
//失败调用callback.onFailure(code,msg);
}
}
----------------------------------------------------------------------分割线上面是网络请求,下面是doAnswer的使用方法
Api api = mock(Api.class);
Mockito.doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
//这里可以获得传给performLogin的参数
Object[] arguments = invocation.getArguments();
//callback是第三个参数下标是2
NetworkCallback callback = (NetworkCallback) arguments[2];
callback.onFailure(500, "Server error");
return 500;
}
}).when(api).get(anyString(), any(HashMap.class), any(NetworkCallback.class));
//这时我们调用api.get()方法
api.get("", null, new NetworkCallback() {
@Override
public void onSuccess(Object data) {
}
@Override
public void onFailure(int code, String msg) {
System.out.print(msg);
}
});
//控制台输出Server error。这样我们在测试时,可以忽略网络请求,然后直接判断请求后的操作
有了mock可以使我们的单元测试更加方便便捷。