• 使用Mockito进行单元测试【1】——mock and verify[转]


    本文转自:http://qiuguo0205.iteye.com/blog/1443344

    1. 为什么使用Mockito来进行单元测试?

    回答这个问题需要回答两个方面,第一个是为什么使用mock?mock其实是一种工具的简称,他最大的功能是帮你把单元测试的耦合分解开,如果你的代码对另一个类或者接口有依赖,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为。

    比如一段代码有这样的依赖:

    当我们需要测试A类的时候,如果没有mock,则我们需要把整个依赖树都构建出来,而使用mock的话就可以将结构分解开,像下面这样:

    还有一个问题是mock工具那么多,为什么我们要用mockito呢?原因很简单:他非常好用!

    他使用执行后验证的模型,语法更简洁并且更加贴近程序员的思考方式,能够模拟类而不仅仅是接口等等。总之如果你想使用mock的话,试用mockito,你不会后悔的:)

    引用的图摘自http://www.theserverside.com/news/1365050/Using-JMock-in-Test-Driven-Development,那里对mock的使用有很好的介绍。

    http://www.sizovpoint.com/2009/03/java-mock-frameworks-comparison.html是一篇非常好的mock工具比较的文章,我就是从它认识的mockito,他也有对mock使用的精彩介绍。

    还有一篇文章总结了mockito的好处:http://java.dzone.com/articles/mockito-pros-cons-and-best

    当然,要想真正了解mockito的好处,就必须写写代码练习一下了。

    2. Mockito使用实例

    这里的代码基本都是从http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html

    摘出来的,然后加上了自己的一些学习验证,这个网页挺重要的,会多次提到,以后就简称”网页“了。让我们通过这些实例来看看mockito的强大功能吧:

    1. 让我们验证一些行为吧

    Java代码 复制代码 收藏代码
    1. //Let's import Mockito statically so that the code looks clearer  
    2. import static org.mockito.Mockito.*;  
    3.   
    4. //mock creation  
    5. List mockedList = mock(List.class);  
    6.   
    7. // using mock object  
    8. mockedList.add("one");  
    9. mockedList.clear();  
    10. mockedList.add("3"); // no verify? OK  
    11.   
    12. // verification  
    13. verify(mockedList).add("one");  
    14. verify(mockedList).clear();  
    15. // verify(mockedList).add("2"); // this will throw an exception  
     

    首先通过这段代码介绍什么是mock:首先使用Mockito的静态方法mock,我们就可以创建一个类的mock实例,这个mock实例拥有这个List的所有方法接口,并且给这些方法以最基本的实现:如果是返回void,他什么都不做,否则他就返回null或0等基本类型的值。比如中间的三句调用了mock的方法,即使将来不验证也没有任何关系。

    在验证阶段,当我们验证这个mock的方法add("one")是否被调用的时候,他不会抛出异常,因为我们确实调用了这个方法,但是当我们验证它是否调用add("2")的时候,就会抛出异常,说明我们没有调用过这个方法,此时的测试就会失败。

    所以验证的意思是”查看我们到底有没有调用过mock的这个方法“。

    2. 它能提供桩[stub]测试吗?

    相信这样的场景我们都遇到过,有一个方法的输入是一个List,在这个方法中我们遍历这个List,读取数据,做相应的操作。往常我们可能需要自己创建一个ArrayList,并且将需要的测试的参数add进list中,这样就可以分别进行测试了。下面看看使用mockito是怎么做到的:

    Java代码 复制代码 收藏代码
    1. // You can mock concrete classes, not only interfaces  
    2. LinkedList mockedList = mock(LinkedList.class);  
    3.   
    4. // stubbing  
    5. when(mockedList.get(0)).thenReturn("first");  
    6. when(mockedList.get(1)).thenThrow(new RuntimeException());  
    7.   
    8. // following prints "first"  
    9. System.out.println(mockedList.get(0));  
    10. // following throws runtime exception  
    11. System.out.println(mockedList.get(1));  
    12. // following prints "null" because get(999) was not stubbed  
    13. System.out.println(mockedList.get(999));  
    14.   
    15. // Although it is possible to verify a stubbed invocation, usually it's just redundant  
    16. // See http://monkeyisland.pl/2008/04/26/asking-and-telling  
    17. verify(mockedList, atLeast(2)).get(0);  
     

    首先我们可以看到mockito是可以mock类而不仅仅是接口的,而stub的语法也非常接近人的阅读习惯:when(mockedList.get(0)).thenReturn("first"); 当调用get(0)的时候返回"first"。

    这里需要注意以下几点:

    【1】mock实例默认的会给所有的方法添加基本实现:返回null或空集合,或者0等基本类型的值。

    【2】当我们连续两次为同一个方法使用stub的时候,他只会只用最新的一次。

    【3】一旦这个方法被stub了,就会一直返回这个stub的值。

    像下面这段代码,你猜会打印什么?

    Java代码 复制代码 收藏代码
    1. when(mockedList.get(0)).thenReturn("first");  
    2. when(mockedList.get(0)).thenReturn("oops");  
    3. System.out.println(mockedList.get(0));  
    4. System.out.println(mockedList.get(0));  

      3. 参数匹配

    下面我们看看mockito强大的参数匹配机制,当mockito执行verify的时候,它实际上对参数执行的是自然地java方式——equals方法。有事我们需要对参数进行灵活匹配的时候就可以用到”参数匹配器“【argument matchers】了

    Java代码 复制代码 收藏代码
    1. // stubbing using built-in anyInt() argument matcher  
    2. when(mockedList.get(anyInt())).thenReturn("element");  
    3.   
    4. // following prints "element"  
    5. System.out.println(mockedList.get(999));  
    6.   
    7. // you can also verify using an argument matcher  
    8. verify(mockedList).get(anyInt());  

    这里的anyInt是mockito内建的众多方法之一,其他可以参考mockito主页上的信息,你也可以调用hamcrest的matchers。

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

    Java代码 复制代码 收藏代码
    1. // correct  
    2. verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));  
    3. // will throw exception  
    4. verify(mock).someMethod(anyInt(), anyString(), "third argument");  

      4. 继续讨论Verification

    前面的例子都是和网页上的例子一一对应的,现在我们集中讨论一下mockito在verify上提供的强大功能,大部分例子都很简单,所以我基本就是简单的罗列:

    # 验证方法被调用的次数 网页例子4

    Java代码 复制代码 收藏代码
    1. //using mock   
    2. mockedList.add("once");  
    3.   
    4. mockedList.add("twice");  
    5. mockedList.add("twice");  
    6.   
    7. mockedList.add("three times");  
    8. mockedList.add("three times");  
    9. mockedList.add("three times");  
    10.   
    11. //following two verifications work exactly the same - times(1) is used by default  
    12. verify(mockedList).add("once");  
    13. verify(mockedList, times(1)).add("once");  
    14.   
    15. //exact number of invocations verification  
    16. verify(mockedList, times(2)).add("twice");  
    17. verify(mockedList, times(3)).add("three times");  
    18.   
    19. //verification using never(). never() is an alias to times(0)  
    20. verify(mockedList, never()).add("never happened");  
    21.   
    22. //verification using atLeast()/atMost()  
    23. verify(mockedList, atLeastOnce()).add("three times");  
    24. verify(mockedList, atLeast(2)).add("five times");  
    25. verify(mockedList, atMost(5)).add("three times");  

    # 按顺序验证  网页例子6

    Java代码 复制代码 收藏代码
    1. // A. Single mock whose methods must be invoked in a particular order  
    2. List singleMock = mock(List.class);  
    3.   
    4. //using a single mock  
    5. singleMock.add("was added first");  
    6. singleMock.add("was added second");  
    7.   
    8. //create an inOrder verifier for a single mock  
    9. InOrder inOrder = inOrder(singleMock);  
    10.   
    11. //following will make sure that add is first called with "was added first, then with "was added second"  
    12. inOrder.verify(singleMock).add("was added first");  
    13. inOrder.verify(singleMock).add("was added second");  
    14.   
    15. // B. Multiple mocks that must be used in a particular order  
    16. List firstMock = mock(List.class);  
    17. List secondMock = mock(List.class);  
    18.   
    19. //using mocks  
    20. firstMock.add("was called first");  
    21. secondMock.add("was called second");  
    22.   
    23. //create inOrder object passing any mocks that need to be verified in order  
    24. InOrder inOrder = inOrder(firstMock, secondMock);  
    25.   
    26. //following will make sure that firstMock was called before secondMock  
    27. inOrder.verify(firstMock).add("was called first");  
    28. inOrder.verify(secondMock).add("was called second");  
    29.   
    30. // Oh, and A + B can be mixed together at will  

    # 确保某些方法没有被调用  网页例子7

    Java代码 复制代码 收藏代码
    1. //using mocks - only mockOne is interacted  
    2. mockOne.add("one");  
    3.   
    4. //ordinary verification  
    5. verify(mockOne).add("one");  
    6.   
    7. //verify that method was never called on a mock  
    8. verify(mockOne, never()).add("two");  
    9.   
    10. //verify that other mocks were not interacted  
    11. verifyZeroInteractions(mockTwo, mockThree);  

    # 从前面的例子我们可以看到,能够很容易地找到冗余的调用  网页例子8

    Java代码 复制代码 收藏代码
    1. //using mocks  
    2. mockedList.add("one");  
    3. mockedList.add("two");  
    4.   
    5. verify(mockedList).add("one");  
    6.   
    7. //following verification will fail   
    8. verifyNoMoreInteractions(mockedList);  

    OK,看过Mockito的 mock 和 verify的能力,你可能已经喜欢上Mockito了,不过这只是Mockito强大功能的一部分,下一篇接着翻译我个人用的最多的stub的功能,真的不可错过,看完之后你绝对能够惊叹Mockito的实力的;-)

  • 相关阅读:
    git 教程
    darknet_ros 踩坑与解决办法
    相机与手臂的校准
    相机的内参外参标定
    VNC windous->linux
    12306 官网硬卧下铺的选择
    /usr/bin/ld: cannot find -lopencv_dep_cudart
    在Windows上安装GPU版Tensorflow
    机器学习基础
    [设计模式]行为型设计模式
  • 原文地址:https://www.cnblogs.com/vvonline/p/4122983.html
Copyright © 2020-2023  润新知