使用類庫需要在build.gradle中加入mockito依賴配置:
testCompile 'org.mockito:mockito-core:2.8.9'
Mock的概念:
所謂的mock就是創(chuàng)建一個(gè)類的虛假的對象茎刚,在測試環(huán)境中逻翁,用來替換掉真實(shí)的對象秒咐,以達(dá)到兩大目的:
1.驗(yàn)證這個(gè)對象的某些方法的調(diào)用情況股囊,調(diào)用了多少次潮饱,參數(shù)是什么等等
2.指定這個(gè)對象的某些方法的行為蝉衣,返回特定的值括尸,或者是執(zhí)行特定的動作
上面說了Mock的概念,下面開始搬磚病毡,寫段代碼示例來說明Mockito的一些常用語法使用濒翻,代碼如下:
/************************************************************
* Author: ssc
* Date: 2018/7/20
* Version: 1.0
* Description: 人的邏輯判斷層
* History:
* <author> <time> <version > <desc>
***********************************************************/
public class Person {
/**
* 獲取該類型性別并進(jìn)行打印
*
* @param type 0代表女生、1代表男生啦膜、其他數(shù)字提示參數(shù)有誤
*/
public void getSex(int type) {
if (type == 0) {
printing("女");
} else if (type == 1) {
printing("男");
} else {
printing("參數(shù)有誤");
}
}
/**
* 打印方法
*
* @param content
*/
public void printing(String content) {
//這里為了簡單我們直接控制臺輸出
System.out.print(content);
}
/**
* 判斷類型是否是男人
*
* @param type
* @return
*/
public boolean isMan(int type) {
//處理邏輯這里為了方便我們直接進(jìn)行簡單判斷
return type == 1;
}
}
1.如何mock出一個(gè)虛假的對象:
Person person = Mockito.mock(Person.class);
2. 如何驗(yàn)證方法調(diào)沒調(diào)用
Mockito.verify(person).getSex(...);這句話的作用是有送,驗(yàn)證person的getSex得到了調(diào)用,調(diào)用次數(shù)為1次僧家。因?yàn)檫@行代碼其實(shí)是:Mockito.verify(person , Mockito.times(1)).getSex(...)的簡寫雀摘,或者說重載方法,注意其中的Mockito.times(1)八拱。因此届宠,如果你想驗(yàn)證一個(gè)對象的某個(gè)方法得到了多次調(diào)用,只需要將次數(shù)傳給Mockito.times()就好了乘粒。
Mockito.verify(person, Mockito.times(3)).getSex(...); //驗(yàn)證person的方法getSex(...)得到了三次調(diào)用豌注。
2.1驗(yàn)證方法的調(diào)用次數(shù)方法有:
- times(n):方法被調(diào)用n次
- never():沒有被調(diào)用
- atLeast(n):至少被調(diào)用n次
- atLeastOnce():至少被調(diào)用1次,相當(dāng)于atLeast(1)
- atMost():最多被調(diào)用n次
代碼演示:
//執(zhí)行1次
verify(person , times(1)).add(...);
//執(zhí)行2次
verify(person , times(2)).add(...);
verify(person , times(3)).add(...);
//從不執(zhí)行, never()等同于times(0)
verify(person , never()).add(...);
//驗(yàn)證至少執(zhí)行1次
verify(person , atLeastOnce()).add(...);
//驗(yàn)證至少執(zhí)行2次
verify(person , atLeast(2)).add(...);
//驗(yàn)證最多執(zhí)行4次
verify(person , atMost(4)).add(...);
3. 在不關(guān)心參數(shù)為什么值的情況下灯萍,如何通過Mock的語法給出方法所需要的參數(shù)對應(yīng)類型
比如上面的例子轧铁,我們在調(diào)用性別后,會走打印方法旦棉,這是我們只關(guān)心打印方法走沒走齿风,而不關(guān)心他的參數(shù)是什么的時(shí)候药薯,我們就要用到Mock的any方法。代碼如下:
Mockito.verify(person).printing(Mockito.anyString());
anyString()表示任何一個(gè)字符串都可以救斑。下面我列舉一些常用的參數(shù)適配方法
3.1參數(shù)適配方法
- anyString
- anyInt
- anyLong
- anyDouble
- anyObject 表示任何對象
- any(clazz)表示任何屬于clazz的對象
- anyCollection
- anyCollectionOf(clazz)
- anyList(Map, set)
- anyListOf(clazz)等等
4. 指定某個(gè)方法的返回值童本,或者是執(zhí)行特定的動作。
4.1指定某個(gè)方法的返回值
Mockito.when(mockObject.targetMethod(args)).thenReturn(desiredReturnValue);
該方法是執(zhí)行mockObject.targetMethod()使其返回特定的值desiredReturnValue脸候,據(jù)需用我們的person來舉例:
//當(dāng)調(diào)用person的isMan方法穷娱,同時(shí)傳入"0"時(shí),返回true
(注意這個(gè)時(shí)候我們調(diào)用person.isMan(0);的時(shí)候值為true而調(diào)用其他數(shù)字則為false运沦,
如果我們忽略數(shù)字泵额,傳任何值都返回true時(shí),就可以用到我們上面講的any()參數(shù)適配方法)
Mockito.when(person.isMan(0)).thenReturn(true);
//當(dāng)調(diào)用person的isMan方法携添,同時(shí)傳入"0"時(shí)嫁盲,返回false(注意同上面解釋一樣)
Mockito.when(person.isMan(0)).thenReturn(false);
相關(guān)語法
- doThrow(Throwable...):進(jìn)行異常測試
@Test
public void testMock() {
List list = mock(List.class);
list.add("123");
//當(dāng)list調(diào)用clear()方法時(shí)會拋出異常
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():指定方法調(diào)用內(nèi)部的真實(shí)邏輯
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對象并不會調(diào)用真實(shí)邏輯
foo.doFoo();
//啥也不會打印出來
doNothing().when(foo).doFoo();
foo.doFoo();
doCallRealMethod().when(foo).doFoo();
//這里會調(diào)用真實(shí)邏輯, 打印出"method doFoo called."信息
foo.doFoo();
//這里會打印出0
System.out.println(foo.getCount());
doCallRealMethod().when(foo).getCount();
//這里會打印出"1"
System.out.println(foo.getCount());
}
4.2執(zhí)行特定的動作
在安裝中經(jīng)常用到網(wǎng)絡(luò)請求數(shù)據(jù),而我們在測試時(shí)忽略網(wǎng)絡(luò)請求這塊時(shí)烈掠,就可以用到mock的執(zhí)行特定的動作:
Mockito.doAnswer(desiredAnswer).when(mockObject).targetMethod(args);
傳給doAnswer()的是一個(gè)Answer對象羞秤,我們想要執(zhí)行什么樣的動作,就在這里面實(shí)現(xiàn)左敌。如:
//登錄操作:
/**
* 網(wǎng)絡(luò)請求返回
*/
public interface NetCallback {
void onSuccess(Object data);
void onFailure(int code, String msg);
}
/**
* 網(wǎng)絡(luò)請求
* Created by xiaochuang on 4/25/16.
*/
public class Api{
public void get(String url, Map<String, String> params, NetworkCallback callback) {
//網(wǎng)絡(luò)請求處理操作邏輯锥腻,這塊忽略寫法
//成功調(diào)用callback.onSuccess(data);
//失敗調(diào)用callback.onFailure(code,msg);
}
}
----------------------------------------------------------------------分割線上面是網(wǎng)絡(luò)請求,下面是doAnswer的使用方法
Api api = mock(Api.class);
Mockito.doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
//這里可以獲得傳給performLogin的參數(shù)
Object[] arguments = invocation.getArguments();
//callback是第三個(gè)參數(shù)下標(biāo)是2
NetworkCallback callback = (NetworkCallback) arguments[2];
callback.onFailure(500, "Server error");
return 500;
}
}).when(api).get(anyString(), any(HashMap.class), any(NetworkCallback.class));
//這時(shí)我們調(diào)用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母谎。這樣我們在測試時(shí),可以忽略網(wǎng)絡(luò)請求京革,然后直接判斷請求后的操作
有了mock可以使我們的單元測試更加方便便捷奇唤。