mockito學習資料:html
http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.htmljava
http://blog.csdn.net/sdyy321/article/details/38757135函數
一、驗證行爲是否發生學習
1
2
3
4
5
6
7
8
|
@Test
public
void
mockedList(){
List mockedList = mock(List.
class
);
mockedList.add(
"one"
);
mockedList.clear();
verify(mockedList).add(
"one"
);
verify(mockedList).clear();
}
|
驗證add和clear是否執行。ui
二、驗證返回值google
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@Test
public
void
two(){
//模擬建立一個List對象
LinkedList mockLinkedList = mock(LinkedList.
class
);
//打樁,當LinkedList調用get(0)方法時,第一次返回zero,第二次n次返回nnnn
when(mockLinkedList.get(
0
)).thenReturn(
"zero"
).thenReturn(
"nnnn"
);
//使用mock對象
System.out.println(mockLinkedList.get(
0
));
System.out.println(mockLinkedList.get(
0
));
System.out.println(mockLinkedList.get(
0
));
//驗證行爲get是否發生
verify(mockLinkedList).get(
0
);
}
|
這裏注意全部的方法都會有返回值,若是沒有設置返回值,那麼就會返回null或者空集、適當的類型。 Stubbing能夠被重寫,也就是同一個參數方法能夠放回不一樣的值,可是已最後一次設置的值爲標準。一旦被 Stubbed,不管方法被調用多少次,都只會返回Stubbed value。最後一次最重要原則。spa
三、參數匹配.net
經過equals()來驗證參數。rest
不一樣的參數返回不一樣的結果:code
1
2
|
when(comparable.compareTo(
"Test"
)).thenReturn(
1
);
when(comparable.compareTo(
"Omg"
)).thenReturn(
2
);
|
一旦你使用了參數匹配器,那麼全部的參數都必須由匹配器給出:
1
2
3
4
5
6
7
8
9
10
11
|
//stubbing using built-in anyInt() argument matcher
when(mockedList.get(anyInt())).thenReturn(
"element"
);
//stubbing using hamcrest (let's say isValid() returns your own hamcrest matcher):
when(mockedList.contains(argThat(isValid()))).thenReturn(
"element"
);
//following prints "element"
System.out.println(mockedList.get(
999
));
//you can also verify using an argument matcher
verify(mockedList).get(anyInt());
|
1
2
3
4
5
|
verify(mock).someMethod(anyInt(), anyString(), eq(
"third argument"
));
//above is correct - eq() is also an argument matcher
verify(mock).someMethod(anyInt(), anyString(),
"third argument"
);
//above is incorrect - exception will be thrown because third argument is given without an argument matcher.
|
四、驗證調用次數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
@Test
public
void
three(){
List mockedList = mock(List.
class
);
mockedList.add(
1
);
mockedList.add(
2
);
mockedList.add(
2
);
mockedList.add(
3
);
mockedList.add(
3
);
mockedList.add(
3
);
//驗證是否被調用一次,等效於下面的times(1),默認的,能夠不寫
verify(mockedList).add(
1
);
verify(mockedList,times(
1
)).add(
1
);
//驗證是否被調用2次
verify(mockedList,times(
2
)).add(
2
);
//驗證是否被調用3次
verify(mockedList,times(
3
)).add(
3
);
//驗證是否從未被調用過
verify(mockedList,never()).add(
4
);
//驗證至少調用一次
verify(mockedList,atLeastOnce()).add(
1
);
//驗證至少調用2次
verify(mockedList,atLeast(
2
)).add(
2
);
//驗證至多調用3次
verify(mockedList,atMost(
3
)).add(
3
);
}
|
add(1)這個方法被調用了1次,add(2)這個被調用了2次。add(3)這個方法被調用了3次,若是將verify(mockedList,times(1)).add(3);運行後那麼就會出現錯誤:
五、模擬方法體拋出異常
1
2
3
4
5
6
|
doThrow(
new
RuntimeException()).when(mockedList).clear();
//following throws RuntimeException:
mockedList.clear();
doThrow(
new
RuntimeException()).when(list).add(
1
);
list.add(
1
);
|
六、驗證執行的順序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@Test
public
void
four(){
List firstList = mock(List.
class
);
List secondList = mock(List.
class
);
//using mocks
firstList.add(
"was called first one mock"
);
secondList.add(
"was called second one mock"
);
//create inOrder object passing any mocks that need to be verified in order
InOrder indOrder = inOrder(firstList,secondList);
indOrder.verify(firstList).add(
"was called first one mock"
);
indOrder.verify(secondList).add(
"was called second one mock"
);
}
|
若是將11,12調換,
indOrder.verify(secondList).add("was called second one mock");
indOrder.verify(firstList).add("was called first one mock");
會出現以下錯誤:
但是若是順序以下:
1
2
3
4
5
|
firstList.add(
"was called first one mock"
);
secondList.add(
"was called second one mock"
);
InOrder indOrder = inOrder(secondList,firstList);
indOrder.verify(firstList).add(
"was called first one mock"
);
indOrder.verify(secondList).add(
"was called second one mock"
);
|
inorder中順序調換後,上面程序竟然沒有出錯?難道我理解錯了。驗證的順序是按照inOrder中給出的,也就是second要在first前面,而在verify中明顯second在first後驗證了,應該出錯啊。
七、模擬對象上沒有相互關係
1
2
3
4
5
6
7
8
9
10
11
|
//using mocks - only mockOne is interacted
mockOne.add(
"one"
);
//ordinary verification
verify(mockOne).add(
"one"
);
//verify that method was never called on a mock
verify(mockOne, never()).add(
"two"
);
//verify that other mocks were not interacted
verifyZeroInteractions(mockTwo, mockThree);
|
八、找出多餘的調用
1
2
3
4
5
6
7
8
9
10
11
12
|
//using mocks
mockedList.add(
"one"
);
mockedList.add(
"two"
);
verify(mockedList).add(
"one"
);
//following verification will fail 檢查是否有未被驗證的行爲
verifyNoMoreInteractions(mockedList);
verify(list,times(
2
)).add(anyInt());
//檢查是否有未被驗證的互動行爲,由於add(1)和add(2)都會被上面的anyInt()驗證到,因此下面的代碼會經過
verifyNoMoreInteractions(list);
|
mockedList還有add("two")沒有驗證,因此出錯。
九、使用註解來mock
這裏注意要在構造函數中初試化mock對象,不然mock對象爲null。
也能夠經過在類上使用註解:@RunWith(MockitoJUnitRunner.class)
這樣就不須要初始化mock了。
十、連續調用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@Test
(expected = RuntimeException.
class
)
public
void
consecutive_calls(){
List mockList = mock(List.
class
);
//模擬連續調用返回指望值,若是分開,則只有最後一個有效
when(mockList.get(
0
)).thenReturn(
0
);
when(mockList.get(
0
)).thenReturn(
1
);
when(mockList.get(
0
)).thenReturn(
2
);
when(mockList.get(
1
)).thenReturn(
0
).thenReturn(
1
).thenThrow(
new
RuntimeException());
assertEquals(
2
,mockList.get(
0
));
assertEquals(
2
,mockList.get(
0
));
assertEquals(
0
,mockList.get(
1
));
assertEquals(
1
,mockList.get(
1
));
//第三次或更多調用都會拋出異常
mockList.get(
1
);
}
|
十一、使用回調來stub
通用:
1
2
3
4
5
6
7
8
9
10
|
when(mock.someMethod(anyString())).thenAnswer(
new
Answer() {
Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
Object mock = invocation.getMock();
return
"called with arguments: "
+ args;
}
});
//Following prints "called with arguments: foo"
System.out.println(mock.someMethod(
"foo"
));
|
使用:
1
2
3
4
5
6
7
8
9
10
11
12
|
@Test
public
void
six(){
List mockList = mock(List.
class
);
when(mockList.get(anyInt())).thenAnswer(
new
Answer<Object>() {
public
Object answer(InvocationOnMock invocation)
throws
Throwable {
Object[] args = invocation.getArguments();
return
"hi:"
+args[
0
];
}
});
assertEquals(
"hi:0"
,mockList.get(
0
));
assertEquals(
"hi:1"
,mockList.get(
1
));
}
|
十二、對於void方法,有系列函數能夠用來處理。
doThrow() doAnswer doNothing doReturn。當一個void的方法有異常拋出時可使用doThrow()。
1三、監控真實對象
當使用spy的時候真正的方法將會被調用,而再也不是stub的對象了,這個和部分mock的思想是同樣的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
@Test
public
void
seven(){
List list =
new
LinkedList();
List spy = spy(list);
//optionally, you can stub out some methods:
when(spy.size()).thenReturn(
100
);
//using the spy calls real methods
spy.add(
"one"
);
spy.add(
"two"
);
//prints "one" - the first element of a list
System.out.println(spy.get(
0
));
//size() method was stubbed - 100 is printed
System.out.println(spy.size());
//optionally, you can verify
verify(spy).add(
"one"
);
verify(spy).add(
"two"
);
}
|
使用spy的時候須要注意一點:有時候是不能使用when語句的
1
2
3
4
5
6
7
8
|
List list =
new
LinkedList();
List spy = spy(list);
//Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
when(spy.get(
0
)).thenReturn(
"foo"
);
//You have to use doReturn() for stubbing
doReturn(
"foo"
).when(spy).get(
0
);
|
1四、設置未stub的調用的默認值
對於沒有stub方法的調用,咱們通常返回null,或者是默認類型。也能夠修改使其返回你指定的值。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@Test
public
void
eight(){
//mock對象使用Answer來對未預設的調用返回默認指望值
List mocklist = mock(List.
class
,
new
Answer(){
public
Object answer(InvocationOnMock invocation)
throws
Throwable {
return
999
;
}
});
//下面的get(1)沒有預設,一般狀況下會返回NULL,可是使用了Answer改變了默認指望值
assertEquals(
999
, mocklist.get(
1
));
//下面的size()沒有預設,一般狀況下會返回0,可是使用了Answer改變了默認指望值
assertEquals(
999
,mocklist.size());
}
|