mockito简单教程
Posted ✧*꧁一品堂.技术学习笔记꧂*✧.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mockito简单教程相关的知识,希望对你有一定的参考价值。
注:本文来源:sdyy321的《mockito简单教程》
API文档:http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html
项目源码:https://github.com/mockito/mockito
首先添加maven依赖
1 <dependency> 2 <groupId>org.mockito</groupId> 3 <artifactId>mockito-all</artifactId> 4 <version>1.9.5</version> 5 <scope>test</scope> 6 </dependency>
当然mockito需要junit配合使用
1 <dependency> 2 <groupId>junit</groupId> 3 <artifactId>junit</artifactId> 4 <version>4.11</version> 5 <scope>test</scope> 6 </dependency>
然后为了使代码更简洁,最好在测试类中导入静态资源
1 import static org.mockito.Mockito.*; 2 import static org.junit.Assert.*;
下面我们开始使用mockito来做测试
1、验证行为
1 @Test 2 public void verify_behaviour(){ 3 //模拟创建一个List对象 4 List mock = mock(List.class); 5 //使用mock的对象 6 mock.add(1); 7 mock.clear(); 8 //验证add(1)和clear()行为是否发生 9 verify(mock).add(1); 10 verify(mock).clear(); 11 }
2、模拟我们所期望的结果
1 @Test 2 public void when_thenReturn(){ 3 //mock一个Iterator类 4 Iterator iterator = mock(Iterator.class); 5 //预设当iterator调用next()时第一次返回hello,第n次都返回world 6 when(iterator.next()).thenReturn("hello").thenReturn("world"); 7 //使用mock的对象 8 String result = iterator.next() + " " + iterator.next() + " " + iterator.next(); 9 //验证结果 10 assertEquals("hello world world",result); 11 } 12 13 @Test(expected = IOException.class) 14 public void when_thenThrow() throws IOException { 15 OutputStream outputStream = mock(OutputStream.class); 16 OutputStreamWriter writer = new OutputStreamWriter(outputStream); 17 //预设当流关闭时抛出异常 18 doThrow(new IOException()).when(outputStream).close(); 19 outputStream.close(); 20 }
3、参数匹配
1 @Test 2 public void with_arguments(){ 3 Comparable comparable = mock(Comparable.class); 4 //预设根据不同的参数返回不同的结果 5 when(comparable.compareTo("Test")).thenReturn(1); 6 when(comparable.compareTo("Omg")).thenReturn(2); 7 assertEquals(1, comparable.compareTo("Test")); 8 assertEquals(2, comparable.compareTo("Omg")); 9 //对于没有预设的情况会返回默认值 10 assertEquals(0, comparable.compareTo("Not stub")); 11 }
1 @Test 2 public void with_unspecified_arguments(){ 3 List list = mock(List.class); 4 //匹配任意参数 5 when(list.get(anyInt())).thenReturn(1); 6 when(list.contains(argThat(new IsValid()))).thenReturn(true); 7 assertEquals(1, list.get(1)); 8 assertEquals(1, list.get(999)); 9 assertTrue(list.contains(1)); 10 assertTrue(!list.contains(3)); 11 } 12 13 private class IsValid extends ArgumentMatcher<List>{ 14 @Override 15 public boolean matches(Object o) { 16 return o == 1 || o == 2; 17 } 18 }
1 @Test 2 public void all_arguments_provided_by_matchers(){ 3 Comparator comparator = mock(Comparator.class); 4 comparator.compare("nihao","hello"); 5 //如果你使用了参数匹配,那么所有的参数都必须通过matchers来匹配 6 verify(comparator).compare(anyString(),eq("hello")); 7 //下面的为无效的参数匹配使用 8 //verify(comparator).compare(anyString(),"hello"); 9 }
4、验证确切的调用次数
1 @Test 2 public void verifying_number_of_invocations(){ 3 List list = mock(List.class); 4 list.add(1); 5 list.add(2); 6 list.add(2); 7 list.add(3); 8 list.add(3); 9 list.add(3); 10 //验证是否被调用一次,等效于下面的times(1) 11 verify(list).add(1); 12 verify(list,times(1)).add(1); 13 //验证是否被调用2次 14 verify(list,times(2)).add(2); 15 //验证是否被调用3次 16 verify(list,times(3)).add(3); 17 //验证是否从未被调用过 18 verify(list,never()).add(4); 19 //验证至少调用一次 20 verify(list,atLeastOnce()).add(1); 21 //验证至少调用2次 22 verify(list,atLeast(2)).add(2); 23 //验证至多调用3次 24 verify(list,atMost(3)).add(3); 25 }
6、验证执行顺序
1 @Test 2 public void verification_in_order(){ 3 List list = mock(List.class); 4 List list2 = mock(List.class); 5 list.add(1); 6 list2.add("hello"); 7 list.add(2); 8 list2.add("world"); 9 //将需要排序的mock对象放入InOrder 10 InOrder inOrder = inOrder(list,list2); 11 //下面的代码不能颠倒顺序,验证执行顺序 12 inOrder.verify(list).add(1); 13 inOrder.verify(list2).add("hello"); 14 inOrder.verify(list).add(2); 15 inOrder.verify(list2).add("world"); 16 }
7、确保模拟对象上无互动发生
1 @Test 2 public void verify_interaction(){ 3 List list = mock(List.class); 4 List list2 = mock(List.class); 5 List list3 = mock(List.class); 6 list.add(1); 7 verify(list).add(1); 8 verify(list,never()).add(2); 9 //验证零互动行为 10 verifyZeroInteractions(list2,list3); 11 }
8、找出冗余的互动(即未被验证到的)
1 @Test(expected = NoInteractionsWanted.class) 2 public void find_redundant_interaction(){ 3 List list = mock(List.class); 4 list.add(1); 5 list.add(2); 6 verify(list,times(2)).add(anyInt()); 7 //检查是否有未被验证的互动行为,因为add(1)和add(2)都会被上面的anyInt()验证到,所以下面的代码会通过 8 verifyNoMoreInteractions(list); 9 10 List list2 = mock(List.class); 11 list2.add(1); 12 list2.add(2); 13 verify(list2).add(1); 14 //检查是否有未被验证的互动行为,因为add(2)没有被验证,所以下面的代码会失败抛出异常 15 verifyNoMoreInteractions(list2); 16 }
9、使用注解来快速模拟
在上面的测试中我们在每个测试方法里都mock了一个List对象,为了避免重复的mock,是测试类更具有可读性,我们可以使用下面的注解方式来快速模拟对象:
1 @Mock 2 private List mockList;
OK,我们再用注解的mock对象试试
1 @Test 2 public void shorthand(){ 3 mockList.add(1); 4 verify(mockList).add(1); 5 }
运行这个测试类你会发现报错了,mock的对象为NULL,为此我们必须在基类中添加初始化mock的代码
1 public class MockitoExample2 { 2 @Mock 3 private List mockList; 4 5 public MockitoExample2(){ 6 MockitoAnnotations.initMocks(this); 7 } 8 9 @Test 10 public void shorthand(){ 11 mockList.add(1); 12 verify(mockList).add(1); 13 } 14 }
或者使用built-in runner:MockitoJUnitRunner
1 @RunWith(MockitoJUnitRunner.class) 2 public class MockitoExample2 { 3 @Mock 4 private List mockList; 5 6 @Test 7 public void shorthand(){ 8 mockList.add(1); 9 verify(mockList).add(1); 10 } 11 }
更多的注解还有@Captor,@Spy,@InjectMocks
10、连续调用
1 @Test(expected = RuntimeException.class) 2 public void consecutive_calls(){ 3 //模拟连续调用返回期望值,如果分开,则只有最后一个有效 4 when(mockList.get(0)).thenReturn(0); 5 when(mockList.get(0)).thenReturn(1); 6 when(mockList.get(0)).thenReturn(2); 7 when(mockList.get(1)).thenReturn(0).thenReturn(1).thenThrow(new RuntimeException()); 8 assertEquals(2,mockList.get(0)); 9 assertEquals(2,mockList.get(0)); 10 assertEquals(0,mockList.get(1)); 11 assertEquals(1,mockList.get(1)); 12 //第三次或更多调用都会抛出异常 13 mockList.get(1); 14 }
11、使用回调生成期望值
1 @Test 2 public void answer_with_callback(){ 3 //使用Answer来生成我们我们期望的返回 4 when(mockList.get(anyInt())).thenAnswer(new Answer<Object>() { 5 @Override 6 public Object answer(InvocationOnMock invocation) throws Throwable { 7 Object[] args = invocation.getArguments(); 8 return "hello world:"+args[0]; 9 } 10 }); 11 assertEquals("hello world:0",mockList.get(0)); 12 assertEquals("hello world:999",mockList.get(999)); 13 }
12、监控真实对象
使用spy来监控真实的对象,需要注意的是此时我们需要谨慎的使用when-then语句,而改用do-when语句
1 @Test(expected = IndexOutOfBoundsException.class) 2 public void spy_on_real_objects(){ 3 List list = new LinkedList(); 4 List spy = spy(list); 5 //下面预设的spy.get(0)会报错,因为会调用真实对象的get(0),所以会抛出越界异常 6 //when(spy.get(0)).thenReturn(3); 7 8 //使用doReturn-when可以避免when-thenReturn调用真实对象api 9 doReturn(999).when(spy).get(999); 10 //预设size()期望值 11 when(spy.size()).thenReturn(100); 12 //调用真实对象的api 13 spy.add(1); 14 spy.add(2); 15 assertEquals(100,spy.size()); 16 assertEquals(1,spy.get(0)); 17 assertEquals(2,spy.get(1)); 18 verify(spy).add(1); 19 verify(spy).add(2); 20 assertEquals(999,spy.get(999)); 21 spy.get(2); 22 }
13、修改对未预设的调用返回默认期望值
1 @Test 2 public void unstubbed_invocations(){ 3 //mock对象使用Answer来对未预设的调用返回默认期望值 4 List mock = mock(List.class,new Answer() { 5 @Override 6 public Object answer(InvocationOnMock invocation) throws Throwable { 7 return 999; 8 } 9 }); 10 //下面的get(1)没有预设,通常情况下会返回NULL,但是使用了Answer改变了默认期望值 11 assertEquals(999, mock.get(1)); 12 //下面的size()没有预设,通常情况下会返回0,但是使用了Answer改变了默认期望值 13 assertEquals(999,mock.size()); 14 }
14、捕获参数来进一步断言
1 @Test 2 public void capturing_args(){ 3 PersonDao personDao = mock(PersonDao.class); 4 PersonService personService = new PersonService(personDao); 5 6 ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class); 7 personService.update(1,"jack"); 8 verify(personDao).update(argument.capture()); 9 assertEquals(1,argument.getValue().getId()); 10 assertEquals("jack",argument.getValue().getName()); 11 } 12 13 class Person{ 14 private int id; 15 private String name; 16 17 Person(int id, String name) { 18 this.id = id; 19 this.name = name; 20 } 21 22 public int getId() { 23 return id; 24 } 25 26 public String getName() { 27 return name; 28 } 29 } 30 31 interface PersonDao{ 32 public void update(Person person); 33 } 34 35 class PersonService{ 36 private PersonDao personDao; 37 38 PersonService(PersonDao personDao) { 39 this.personDao = personDao; 40 } 41 42 public void update(int id,String name){ 43 personDao.update(new Person(id,name)); 44 } 45 }
15、真实的部分mock
1 @Test 2 public void real_partial_mock(){ 3 //通过spy来调用真实的api 4 List list = spy(new ArrayList()); 5 assertEquals(0,list.size()); 6 A a = mock(A.class); 7 //通过thenCallRealMethod来调用真实的api 8 when(a.doSomething(anyInt())).thenCallRealMethod(); 9 assertEquals(999,a.doSomething(999)); 10 } 11 12 13 class A{ 14 public int doSomething(int i){ 15 return i; 16 } 17 }
16、重置mock‘
1 @Test 2 public void reset_mock(){ 3 List list = mock(List.class); 4 when(list.size()).thenReturn(10); 5 list.add(1); 6 assertEquals(10,list.size()); 7 //重置mock,清除所有的互动和预设 8 reset(list); 9 assertEquals(0,list.size()); 10 }
以上是关于mockito简单教程的主要内容,如果未能解决你的问题,请参考以下文章