mockito学习资料:
http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html
http://blog.csdn.net/sdyy321/article/details/38757135
?
1、验证行为是否发生
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是否执行。
2、验证返回值
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。最后一次最重要原则。
3、参数匹配
通过equals()来验证参数。
不同的参数返回不同的结果:
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.
|
4、验证调用次数
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);运行后那么就会出现错误:
5、模拟方法体抛出异常
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 );
|
6、验证执行的顺序
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后验证了,应该出错啊。
7、模拟对象上没有相互关系
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);
|
8、找出多余的调用
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")没有验证,所以出错。
9、使用注解来mock
这里注意要在构造函数中初试化mock对象,否则mock对象为null。
也可以通过在类上使用注解:@RunWith(MockitoJUnitRunner.class)
这样就不需要初始化mock了。
10、连续调用
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 );
}
|
11、使用回调来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 ));
}
|
12、对于void方法,有系列函数可以用来处理。
doThrow() doAnswer doNothing doReturn。当一个void的方法有异常抛出时可以使用doThrow()。
13、监控真实对象
当使用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 );
|
14、设置未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());
}
|
时间: 2024-10-06 02:29:57