• mockito框架


    2016-04-09 15:56:26

    参考自

    http://www.cnblogs.com/silence-hust/p/5017233.html

    http://blog.csdn.net/sdyy321/article/details/38757135

    首先创建一个maven工程

    在pom文件中,存在如下依赖

          <dependencies>
                 <dependency>
                  <groupId>junit</groupId>
                  <artifactId>junit</artifactId>
                  <version>4.11</version>
                            <scope>test</scope>
              </dependency>
              <dependency>
                  <groupId>org.mockito</groupId>
                  <artifactId>mockito-all</artifactId>
                  <version>1.9.5</version>
                            <scope>test</scope>
              </dependency>
          </dependencies>

     1、验证行为是否发生

    @Test
        public void mockedList(){
            List mockedList = mock(List.class);
            mockedList.add("one");
            mockedList.clear();
            //验证add("one")和clear()行为是否发生
            verify(mockedList).add("one");
            verify(mockedList).clear();
        }

    2、验证返回值

    @Test
        public void two(){
            //模拟创建一个List对象
            LinkedList mockLinkedList = mock(LinkedList.class);
     
            //打桩,当LinkedList调用get(0)方法时,第一次返回hello,第二次n次返回world
            when(mockLinkedList.get(0)).thenReturn("hello").thenReturn("world");
            String result = mockLinkedList.get(0) + " " + mockLinkedList.get(0) + " " + mockLinkedList.get(0);  
     
            //使用mock对象
            System.out.println(mockLinkedList.get(0));
            System.out.println(mockLinkedList.get(0));
            System.out.println(mockLinkedList.get(0));
           
            assertEquals("hello world world",result);  
        } 

    这里注意所有的方法都会有返回值,如果没有设置返回值,那么就会返回null或者空集、适当的类型。 Stubbing可以被重写,也就是同一个参数方法可以放回不同的值,但是以最后一次设置的值为标准。一旦被 Stubbed,无论方法被调用多少次,都只会返回Stubbed value。最后一次最重要原则。

    第一次运行打印 hello world world,这是第二次运行测试打印 world world world。

    3、参数匹配

    @Test  
        public void with_arguments(){  
            Comparable comparable = mock(Comparable.class);  
            //预设根据不同的参数返回不同的结果  
            when(comparable.compareTo("Test")).thenReturn(1);  
            when(comparable.compareTo("Omg")).thenReturn(2);  
            assertEquals(1, comparable.compareTo("Test"));  
            assertEquals(2, comparable.compareTo("Omg"));  
            //对于没有预设的情况会返回默认值  
            assertEquals(0, comparable.compareTo("Not stub"));  
        }  

    除了匹配给定参数外,还可以使用参数匹配器 argumentMatchers,更加灵活

    @Test  
        public void argumentMatchersTest(){  
            List list = mock(List.class);  
            //匹配任意int类型的值 
            when(list.get(anyInt())).thenReturn(1);
            assertEquals(1, list.get(1));  
            verify(list).get(anyInt());
            assertEquals(1, list.get(999)); 
        }  

    若方法中的某一个参数使用了matcher,则所有的参数都必须使用matcher:

    @Test  
        public void argumentMatchersTest2(){  
            Map map = mock(Map.class);  
            //匹配任意参数  
            when(map.put(anyInt(),anyString())).thenReturn("world");  
            assertEquals("world", map.put(1,"hello"));
            //以下三种验证都可通过测试
            verify(map).put(anyInt(),anyString());
            verify(map).put(anyInt(),eq("hello"));
            verify(map).put(eq(1),eq("hello"));
        } 

    4、验证调用次数

    @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);
        }

    5、模拟抛出异常

    @Test(expected = IOException.class)  
        public void when_thenThrow() throws IOException {  
            OutputStream outputStream = mock(OutputStream.class);  //预设当流关闭时抛出异常 ,因为close()返回类型为void,采用了doThrow 形式
            doThrow(new IOException()).when(outputStream).close();
            outputStream.close();  
        }
        

    对于返回类型为void的方法,有系列函数可以用来处理,如doThrow, doAnswer, doNothing, doReturn。

    6、验证执行的顺序

    @Test
        public void four(){
            List firstList = mock(List.class);
            List secondList = mock(List.class);
            //using mocks
            firstList.add("was called first one mock");
            firstList.add("was called second one mock");
            secondList.add("was called third one mock");
            secondList.add("was called fourth one mock");
            //create inOrder object passing any mocks that need to be verified in order
            
           // InOrder indOrder = inOrder(firstList,secondList);
            InOrder indOrder = inOrder(secondList,firstList);
           //实际上两种顺序都通过测试了
          
            indOrder.verify(firstList).add("was called first one mock");
            indOrder.verify(firstList).add("was called second one mock");
            indOrder.verify(secondList).add("was called third one mock");
            indOrder.verify(secondList).add("was called fourth one mock");
     
        }

    7、验证零互动

    @Test  
        public void verify_interaction(){  
            List list = mock(List.class);  
            List list2 = mock(List.class);  
            List list3 = mock(List.class);  
            list.add(1);  
            verify(list).add(1);  
            verify(list,never()).add(2);  
            //验证零互动行为  
            verifyZeroInteractions(list2,list3);  
        }  

    8、找出冗余的互动(即未被验证到的)

    @Test
        public void find_redundant_interaction(){  
            List list = mock(List.class);  
            list.add(1);  
            list.add(2);  
            verify(list,times(2)).add(anyInt());  
           //检查是否有未被验证的互动行为,因为add(1)和add(2)都会被上面的anyInt()验证到,所以下面的代码会通过  
            verifyNoMoreInteractions(list);  
          
           //下面因为只验证了add(1),add(2)没有被验证,所以下面的代码会失败抛出异常  
           //  List list2 = mock(List.class);  
           // list2.add(1);  
           // list2.add(2);  
           //verify(list2).add(1);  
           // verifyNoMoreInteractions(list2);  
        }  

    9、使用注解来快速模拟

    在上面的测试中我们在每个测试方法里都mock了一个List对象,为了避免重复的mock,是测试类更具有可读性,我们可以使用下面的注解方式来快速模拟对象: 

    public class MockDemoTest2 {
        @Mock 
        private List mockList;  
      
        public MockDemoTest2(){  
            MockitoAnnotations.initMocks(this);  
        }  
      
        @Test  
        public void shorthand(){  
            mockList.add(1);  
            verify(mockList).add(1);  
        }  
    }

    注意要在构造函数中初试化mock对象,否则mock对象为null。也可以通过在类上使用注解:@RunWith(MockitoJUnitRunner.class)  ,这样就不需要初始化mock了。

    @RunWith(MockitoJUnitRunner.class) 
    public class MockDemoTest2 {
    
        @Mock 
        private List mockList;  
      
       /* public MockDemoTest2(){  
            MockitoAnnotations.initMocks(this);  
        }  
      */
        @Test  
        public void shorthand(){  
            mockList.add(1);  
            verify(mockList).add(1);  
        }  
    
    }

    10、连续调用

    @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、使用回调生成期望值

    @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); 
        }

    12、监控真实对象

    当使用spy的时候真正的方法将会被调用,而不再是stub的对象了,这个和部分mock的思想是一样的。

    @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-then语句,而改用do-when语句

    @Test(expected = IndexOutOfBoundsException.class)  
        public void spy_on_real_objects(){  
            List list = new LinkedList();  
            List spy = spy(list);  
            //下面预设的spy.get(0)会报错,因为会调用真实对象的get(0),所以会抛出越界异常  
            //when(spy.get(0)).thenReturn(3);  
          
            //使用doReturn-when可以避免when-thenReturn调用真实对象api  
            doReturn(999).when(spy).get(999);  
            //预设size()期望值  
            when(spy.size()).thenReturn(100);  
            //调用真实对象的api  
            spy.add(1);  
            spy.add(2);  
            assertEquals(100,spy.size());  
            assertEquals(1,spy.get(0));  
            assertEquals(2,spy.get(1));  
            verify(spy).add(1);  
            verify(spy).add(2);  
            assertEquals(999,spy.get(999));  
            spy.get(2);  
        }  

    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()); 
        }

    14、捕获参数来进一步断言

     @Test  
     public void capturing_args(){  
        PersonDao personDao = mock(PersonDao.class);  
        PersonService personService = new PersonService(personDao);  
      
        ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);  
        personService.update(1,"jack");  
        verify(personDao).update(argument.capture());  
        assertEquals(1,argument.getValue().getId());  
        assertEquals("jack",argument.getValue().getName());  
    }  
      
     class Person{  
        private int id;  
        private String name;  
      
        Person(int id, String name) {  
            this.id = id;  
            this.name = name;  
        }  
      
        public int getId() {  
            return id;  
        }  
      
        public String getName() {  
            return name;  
        }  
    }  
      
    interface PersonDao{  
        public void update(Person person);  
    }  
      
    class PersonService{  
        private PersonDao personDao;  
      
        PersonService(PersonDao personDao) {  
            this.personDao = personDao;  
        }  
      
        public void update(int id,String name){  
            personDao.update(new Person(id,name));  
        }  
    } 

    15、真实的部分mock

    @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;  
            }  
        }  
     

    16、重置mock

    @Test  
        public void reset_mock(){  
            List list = mock(List.class);  
            when(list.size()).thenReturn(10);  
            list.add(1);  
            assertEquals(10,list.size()); 
            verify(list).add(1);
            //重置mock,清除所有的互动和预设  
            reset(list);  
            assertEquals(0,list.size());  
        }  
  • 相关阅读:
    如果世界变慢为原先的百万分之一
    N880e 刷机记录和一些经验
    Linux Shell Commands 常用Linux命令行
    适用于单选的jQuery Autocomplete插件SelectToAutocomplete
    PHP5.3 中的Warning: date_default_timezone_set
    Apache中RewriteCond规则和QUERY_STRING参数
    网站网络编辑日常工作流程
    网站编辑与传统媒体编辑的区别及特点
    使用JCaptcha生成验证码
    Debian 7 Wheezy 安装Oracle JDK6, JDK5和Tomcat6
  • 原文地址:https://www.cnblogs.com/kanhaiba/p/5454280.html
Copyright © 2020-2023  润新知