zoukankan      html  css  js  c++  java
  • Mockito--完整功能介绍(转)

    public interface DBAccess {
        int delete(String moi,String moc) throws Exception;
        void create(String moi,String moc,Map<String,Object> attributes)throws Exception;
        List<Map<String, Object>> select(String moi,String moc,String[] attributes) throws Exception;
        int update(String moi,String moc,Map<String,Object> attributes)throws Exception;
    }

    Mock:

            dbAccess=mock(DBAccess.class);
            Collection<String> attrs=anyCollectionOf(String.class);
            when(dbAccess.select(anyString(), anyString(),attrs.toArray(new String[attrs.size()]) )).thenReturn(resultList);
    
    
    
                verify(dbAccess,times(wantedNumberOfInvocations)).create(anyString(), anyString(), anyMapOf(String.class, Object.class));

    回到官网:http://mockito.org/,打开documentation可以看到原文。

    强烈建议不熟悉Mockito的同学先看看我写的Mockito(一)入门篇和(二)实例篇之后再来看这篇文章。

    因为只有看了前两篇文章才明白mockito的本质以及该如何使用它。

    下面是按原文 翻译+注释 的对Mockito全部功能的介绍。

    1, 使用mockito验证行为。

    //首先要importMockito.

    import static org.mockito.Mockito.*;

    //mock creation

    List mockedList = mock(List.class);

    //using mock object

    mockedList.add("one");

    mockedList.clear();

    //验证add方法是否在前面被调用了一次,且参数为“one”。clear方法同样。

    verify(mockedList).add("one");

    verify(mockedList).clear();

    //下面的验证会失败。因为没有调用过add("two")。

    verify(mockedList).add("two");

    原文中的一句话很重要:Once created, mock will remember all interactions.所以mockito知道前面是否调用过某方法。

    2, 使方法调用返回期望的值。也被称为stubbing

    //You can mock concrete classes, not only interfaces

    LinkedList mockedList = mock(LinkedList.class);

    //stubbing。当get(0)被调用时,返回"first". 方法get(1)被调用时,抛异常。

    when(mockedList.get(0)).thenReturn("first");

    when(mockedList.get(1)).thenThrow(new RuntimeException());

    //following prints "first"

    System.out.println(mockedList.get(0));

    //following throws runtime exception

    System.out.println(mockedList.get(1));

    //following prints "null" because get(999) was not stubbed

    System.out.println(mockedList.get(999));

    默认情况下,对于所有有返回值且没有stub过的方法,mockito会返回相应的默认值。

    对于内置类型会返回默认值,如int会返回0,布尔值返回false。对于其他type会返回null。

    这里一个重要概念就是: mock对象会覆盖整个被mock的对象,因此没有stub的方法只能返回默认值。

    //重复stub两次,则以第二次为准。如下将返回"second":

    when(mockedList.get(0)).thenReturn("first");

    when(mockedList.get(0)).thenReturn("second");

    //如果是下面这种形式,则表示第一次调用时返回“first”,第二次调用时返回“second”。可以写n多个。

    when(mockedList.get(0)).thenReturn("first").thenReturn("second");

    但是,如果实际调用的次数超过了stub过的次数,则会一直返回最后一次stub的值。

    如上例,第三次调用get(0)时,则会返回"second".

    3, 参数匹配

    在上例中如果想实现get(任意整数)时,都返回“element”时,该怎么做呢?很简单。

    //stubbing 使用了内置的anyint() matcher.

    when(mockedList.get(anyInt())).thenReturn("element");

    //因此除了anyint()之外,还有其他很多matcher。这里请参考原文。

    //使用了matcher一样可以验证被调用的次数。

    verify(mockedList).get(anyInt());

    这里有一个限制就是,如果在调用方法时需要传入多个参数,其中一个参数使用了argument matcher,那么所有的参数必须都是matcher。

    不可以matcher和实际的参数混着用。

    这里也可以使用custom argument matcher。因为很多时候输入参数不是build-in 类型,而是我们自己写的一些类,或特殊对象。

    这时要使用argument matcher,就必须订制特殊的matcher了。

    下例是一个特殊的matcher的实例,这个matcher可以匹配任何file对象。

    public class SayHiTest {

     @Test
     public void testSayHi() throws Exception {
         File mock = mock(File.class); //首先mock File类。
         //注意new IsAnyFiles()并不是一个matcher,需要调用argThat(new IsAnyFiles()))才返回一个matcher。

         //下句中stub:当调用renameTo方法时,返回false。该方法参数可以是任意file对象。

         when(mock.renameTo(argThat(new IsAnyFiles()))).thenReturn(false); 
         mock.renameTo(new File("test")); 

         //下句verify renameTo方法被调用了一次,同时输入参数是任意file。
         verify(mock).renameTo(argThat(new IsAnyFiles()));
     }
    }
     
    class IsAnyFiles extends ArgumentMatcher<File> {
        public boolean matches(Object file) {
            return file.getClass() == File.class;
        }
     }

    另外一个参数匹配的例子:

                class IsSOAPMessage extends ArgumentMatcher<SOAPMessage> {

                            public boolean matches(Object soapMessage) {

                                        return (soapMessage instanceof SOAPMessage) || soapMessage==null;

                            }

                }

    //上面的macther不仅可以匹配任意的SOAPMessage对象,如果输入参数为空也可以匹配上。

    这里说一下我犯过的一个错误。

    我在做参数匹配的时候,没有考虑到输入参数为空的情况,导致matcher匹配不上,进而stub的行为无法生效。

    其实在发现mock对象没有想自己想象的方式工作时,最好的方法就是debug进去,首先要先确定mock对象是不是真的传递进去了。然后再一步步的debug。

    通常遇到的两种情况就是1,mock对象没有传递进去。2,参数没有匹配上。

    4, 验证方法被调用了特定次数/至少x次/最多x次/从未被调用

    //是否add("twice")被调用了两次。

     verify(mockedList, times(2)).add("twice");

    //验证add("twice")被调用了至少一次。以及其他。

    verify(mockedList, atLeastOnce()).add("twice");

    verify(mockedList, atLeast(2)).add("twice");

    verify(mockedList, atMost(5)).add("twice");

    verify(mockedList, never()).add("twice");

    5, 调用方法时抛出异常

    doThrow(new RuntimeException()).when(mockedList).clear();

    后面还会再介绍几个类似的方法,例如doReturn()。

    6, 验证顺序

    //下面的代码验证firstMock先被调用,secondMock后被调用。

    inOrder.verify(firstMock).add("was called first");

    inOrder.verify(secondMock).add("was called second");

    7, 验证mock之间没有相互作用6,7都不是很明白实际意义是什么。

    8, 找到冗余的调用

    用never()就可以实现,不多说

    9, 使用@mock 定义mock。


    之前都是使用mock()来模拟一个对象。用@mock是一个shorthand。

    public class ArticleManagerTest {

    @Mock private ArticleCalculator calculator;

    @Mock private ArticleDatabase database;

    @Mock private UserProvider userProvider;

    private ArticleManager manager;

    之后再继续介绍mockito复杂一点的功能。

    http://blog.csdn.net/onlyqi/article/details/6544989

  • 相关阅读:
    在rhel6上安装Python 2.7和Python 3.3
    RHEL7 -- Linux搭建FTP虚拟用户
    RHCE7 -- IPv6
    RHEL7 -- nmcli的使用
    设置Adobe Reader打开PDF文件保持记忆功能
    iptalbes -F
    服务器IP地址后修改SQL Server配置
    配置SELINUX
    11G新特性 -- 分区表和增量统计信息
    11G新特性 -- Statistics Preferences
  • 原文地址:https://www.cnblogs.com/softidea/p/4168522.html
Copyright © 2011-2022 走看看