美文网首页
单元测试之Mockito

单元测试之Mockito

作者: sylcrq | 来源:发表于2016-11-14 11:54 被阅读400次

    关键词:Mockito

    以下内容翻译整理自:
    Mockito latest documentation
    [译] 使用强大的 Mockito 测试框架来测试你的代码

    Unit tests with Mockito - Tutorial
    When/how to use Mockito Answer(需要翻墙)
    使用Mockito对异步方法进行单元测试

    2. 使用mock对象进行测试

    单元测试应该尽可能隔离其他类或系统的影响。

    • dummy object
    • Fake objects
    • stub class
    • mock object

    可以使用mock框架创建mock对象来模拟类,mock框架允许在运行时创建mock对象,并定义它们的行为。
    Mockito是目前流行的mock框架,可以配合JUnit使用。Mockito支持创建和设置mock对象。使用Mockito可以显著的简化对那些有外部依赖的类的测试。

    • mock测试代码中的外部依赖
    • 执行测试
    • 验证代码是否执行正确
    mockito

    4. 使用Mockito API

    • Static imports
      添加static import org.mockito.Mockito.*;

    • Creating and configuring mock objects with Mockito

    Mockito支持通过静态方法mock()创建mock对象,也可以使用@Mock注解。如果使用注解的方式,必须初始化mock对象。使用MockitoRule,调用静态方法MockitoAnnotations.initMocks(this)初始化标示的属性字段。

    import static org.mockito.Mockito.*;
    
    public class MockitoTest {
        @Mock
        MyDatabase databaseMock;
      
        @Rule
        public MockitoRule mockitoRule = MockitoJUnit.rule();
     
        @Test
        public void testQuery() {
            ClassToTest t = new ClassToTest(databaseMock);
            boolean check = t.query("* from t"); 
            assertTrue(check);
            verify(databaseMock).query("* from t"); 
        }
    }
    
    • Configuring mocks

      • when(…​.).thenReturn(…​.)用于指定条件满足时的返回值,也可以根据不同的传入参数返回不同的值。
      • doReturn(…​).when(…​).methodCall作用类似,但是用于返回值为void的函数。
    • Verify the calls on the mock objects
      Mockito会跟踪mock对象所有的函数调用以及它们的参数,可以用verify()验证
      一个函数有没有被调用with指定的参数。这个被称为"behavior testing"

    • Wrapping Java objects with Spy
      @Spyspy()方法用于封装实际的对象。除非有特殊声明(stub),都会真正的调用对象的方法。

    • Using @InjectMocks for dependency injection via Mockito

      • You also have the @InjectMocks annotation which tries to do constructor, method or field dependency injection based on the type.
    • Capturing the arguments
      ArgumentCaptor允许我们在verification期间访问函数的参数。在捕获这些函数参数后,可以用于测试。

    • Limitations
      以下不能使用Mockito测试
      • final classes
      • anonymous classes
      • primitive types
    1. Mockito Answer的使用

    A common usage of Answer is to stub asynchronous methods that have callbacks.

    doAnswer(new Answer<Void>() {
        public Void answer(InvocationOnMock invocation) {
        Callback callback = (Callback) invocation.getArguments()[0];
        callback.onSuccess(cannedData);
        return null;
        }
    }).when(service).get(any(Callback.class));
    

    Answer can also be used to make smarter stubs for synchronous methods.

    when(translator.translate(any(String.class))).thenAnswer(reverseMsg())
    ...
    // extracted a method to put a descriptive name
    private static Answer<String> reverseMsg() {
        return new Answer<String>() {
            public String answer(InvocationOnMock invocation) {
                return reverseString((String) invocation.getArguments()[0]));
            }
        }
    }
    

    Mockito限制

    • final classes
    • anonymous classes
    • primitive types

    Mockito示例

    1. Let's verify some behaviour!
    //Let's import Mockito statically so that the code looks clearer 
    import static org.mockito.Mockito.*; 
    
    //mock creation 
    List mockedList = mock(List.class); 
    
    //using mock object 
    mockedList.add("one"); 
    mockedList.clear(); 
    
    //verification 
    verify(mockedList).add("one"); 
    verify(mockedList).clear();
    

    验证某些操作是否执行

    Once created, a mock will remember all interactions. Then you can selectively verify whatever interactions you are interested in.

    2. How about some stubbing?
    //You can mock concrete classes, not just interfaces 
    LinkedList mockedList = mock(LinkedList.class); 
    
    //stubbing 
    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)); 
    
    //Although it is possible to verify a stubbed invocation, usually **it's just redundant** 
    //If your code cares what get(0) returns, then something else breaks (often even before verify() gets executed). 
    //If your code doesn't care what get(0) returns, then it should not be stubbed. Not convinced? See [here](http://monkeyisland.pl/2008/04/26/asking-and-telling). 
    verify(mockedList).get(0);
    

    By default, for all methods that return a value, a mock will return either null, a a primitive/primitive wrapper value, or an empty collection, as appropriate. For example 0 for an int/Integer and false for a boolean/Boolean.

    3. Argument matchers
    //stubbing using built-in anyInt() argument matcher 
    when(mockedList.get(anyInt())).thenReturn("element"); 
    
    //stubbing using custom matcher (let's say isValid() returns your own matcher implementation): 
    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()); 
    
    //**argument matchers can also be written as Java 8 Lambdas** 
    verify(mockedList).add(someString -> someString.length() > 5);
    

    If you are using argument matchers, all arguments have to be provided by matchers.

    5. Stubbing void methods with exceptions
    doThrow(new RuntimeException()).when(mockedList).clear(); 
    
    //following throws RuntimeException: 
    mockedList.clear();
    
    6. Verification in order
    // A. Single mock whose methods must be invoked in a particular order 
    List singleMock = mock(List.class); 
    
    //using a single mock 
    singleMock.add("was added first"); 
    singleMock.add("was added second"); 
    
    //create an inOrder verifier for a single mock 
    InOrder inOrder = inOrder(singleMock); 
    
    //following will make sure that add is first called with "was added first, then with "was added second" 
    inOrder.verify(singleMock).add("was added first"); 
    inOrder.verify(singleMock).add("was added second"); 
    
    // B. Multiple mocks that must be used in a particular order 
    List firstMock = mock(List.class); 
    List secondMock = mock(List.class); 
    
    //using mocks 
    firstMock.add("was called first"); 
    secondMock.add("was called second"); 
    
    //create inOrder object passing any mocks that need to be verified in order 
    InOrder inOrder = inOrder(firstMock, secondMock); 
    
    //following will make sure that firstMock was called before secondMock 
    inOrder.verify(firstMock).add("was called first"); 
    inOrder.verify(secondMock).add("was called second"); 
    
    // Oh, and A + B can be mixed together at will
    
    7. Making sure interaction(s) never happened on mock
    //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. Finding redundant invocations
    //using mocks 
    mockedList.add("one"); 
    mockedList.add("two"); 
    
    verify(mockedList).add("one"); 
    
    //following verification will fail 
    verifyNoMoreInteractions(mockedList);
    

    verifyNoMoreInteractions() is a handy assertion from the interaction testing toolkit. Use it only when it's relevant. Abusing it leads to overspecified, less maintainable tests.

    相关文章

      网友评论

          本文标题:单元测试之Mockito

          本文链接:https://www.haomeiwen.com/subject/nojhpttx.html