c,判斷你要得到什麼樣的結果,也就是你的函數要改變哪些變量的值,然後在UT的最後用Assert斷言來對這些期望值進行預測判斷
下面寫一個例子,本例要驗證fillModel這個函數,它的作用是將一個List<Models>中每一個model的defined屬性設置爲true,需要調用外部的依賴itemService來獲取一個model2的defined值,然後將這個值填入model的defined屬性中。
本例中輸入參數是一個List<Models>,一個model裏填入kdtId和id兩個屬性,所以首先進行參數準備(見代碼);
本例需要依賴itemService下的getSpuMap方法,希望這個方法返回一個map,而這個map中value元素model2的defined屬性經過這個方法被設置爲true,注意這個方法不是我們寫的,所以在這裏需要被mock掉,而mock掉後返回的結果是希望含有defined屬性爲true的。
所以,首先我們構造一個這個itemService方法的返回值,也就是一個map,這個map的value是一個model2類,而model2的defined被我們預先設置爲true;
然後用when語句mock掉itemService方法,使其返回我們構造好的這個map:
when(itemService.getSpuMap(anyLong(), anyList())).thenReturn(map);
最後調用我們要測驗的方法,然後查看調用後model的defined是否和我們預設的model2的值一樣。
需要注意的是,因爲我們要測試的fillModel這個方法是需要被實際執行的,不能被mock,所以這個方法的類(通常也就是你的測試類對應的方法類)需要加上@InjectMock註解。而其中依賴的itemService.getSpuMap方法不是我們寫的,我們只是依賴於它的返回值,這個類的初始化要加上@Mock註解。
@Test public void test_fillModel(){ //參數準備 Long kdtId = 100L; Long id = 10002L; Model model = new Model(); model.setKdtId(kdtId); model.setId(id); List<Model> models = Lists.newArrayList(model); //做好預期的結果 Map<Long, Model2> map = new HashMap<>(); Model2 model2 = new Model2(); model2.setItemId(id); model2.setKdtId(kdtId); model2.setDefined(true); spuMap.put(10002L,model2); //通過when語句mock出fillHasMultiSku函數中所依賴的getSpuMap資源,該資源輸入任意參數,得到之前做好的預期結果spyMap when(itemService.getSpuMap(anyLong(), anyList())).thenReturn(map); //實際執行fillHasMultiSku函數,models中填入信息 itemListInnerService.fillModel(models); Assert.assertEquals(models.get(0).isDefined(),itemSkuTotalModel.isDefined()); }
另外還有很多實用Mockito進行測試的小問題,舉幾個例子:
1,巧用verify語句
verify是用來驗證某函數的執行與否,執行幾次,沒有被執行等
@Test
public void verifying_number_of_invocations(){
List list = mock(List.class);
list.add(1);
list.add(2);
list.add(2);
list.add(3);
list.add(3);
list.add(3);
//驗證是否被調用一次,等效於下面的times(1)
verify(list).add(1);
verify(list,times(1)).add(1);
//驗證是否被調用2次
verify(list,times(2)).add(2);
//驗證是否被調用3次
verify(list,times(3)).add(3);
//驗證是否從未被調用過
verify(list,never()).add(4);
//驗證至少調用一次
verify(list,atLeastOnce()).add(1);
//驗證至少調用2次
verify(list,atLeast(2)).add(2);
//驗證至多調用3次
verify(list,atMost(3)).add(3);
2,用doThrow驗證拋出異常
@Test(expected = RuntimeException.class)
public void doThrow_when(){
List list = mock(List.class);
doThrow(new RuntimeException()).when(list).add(1);
list.add(1);
}
3,用spy來真正調用真實的api
@Test
public void real_partial_mock(){
//通過spy來調用真實的api
List list = spy(new ArrayList());
assertEquals(0,list.size());
A a = mock(A.class);
//通過thenCallRealMethod來調用真實的api
when(a.doSomething(anyInt())).thenCallRealMethod();
assertEquals(999,a.doSomething(999));
}
class A{
public int doSomething(int i){
return i;
}
}
4,使用 new Answer()來對未預設的調用更改默認期望值
@Test
public void unstubbed_invocations(){
//mock對象使用Answer來對未預設的調用返回默認期望值
List mock = mock(List.class,new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return 999;
}
});
//下面的get(1)沒有預設,通常情況下會返回NULL,但是使用了Answer改變了默認期望值
assertEquals(999, mock.get(1));
//下面的size()沒有預設,通常情況下會返回0,但是使用了Answer改變了默認期望值
assertEquals(999,mock.size());
}
Mock的使用相對簡單,但是有很多小細節需要注意,以後使用過程中遇到的問題會更在後面。