Java Unit Test Tool - Mockito

今天聊聊在java unit test里面常用的一个工具:Mockito。

在写unit test的时候,我们有时候会遇到一个问题:难以创建某些class的instance,比如dynamoDB client。我们不想在unit test里真的去call dynamoDB,但又需要对code进行test。这时候就可以用Mockito这个工具去模拟call dynamoDB。

Wikipedia上说:

Mockito is an open source testing framework for java released under the MIT License. The framework allows the creation of test double objects (mock objects) in automated unit tests for the purpose of Test-driven Development (TDD) or Behavior Driven Development (BDD).

简言之,Mockito是一个用于测试的框架。

举例说明它的用法:

import org.junit.Assert;
import org.mockito.Mockito.mock;

// mock creation
List mockedList = mock(List.class);

when(mockedList.size()).thenReturn(123);
Assert.assertEquals(123, mockedList.size());

这里并没有new一个List的instance,而是用mock模拟List的instance,这个mock的instance(mockedList)拥有List的所有method和field。但用了mock,可以指定一些method的行为,比如如果mockedList call method .size(),无论实际size多少,都返回123。when(...).thenReturn()...的过程也叫Stub,中文有人叫"打桩"/"存根"。

Tips

  • 当我们连续两次为同一个method用stub的时候,它只会只用最新的一次。
  • 被mock的instance(在例子中是mockedList),会使它所有真正的method失效。就是说不被stub的method会返回null或报错。

其他常用形式:

// if no return
doNothing().when(mockedEvent).fire(...);

// if want to throw exception
when(mockedEvent.fire(...)).thenThrow(new RuntimeException());  

// if want to pass argument
when(mockedList.get(0)).thenReturn("foo");
when(mockedList.get(anyInt())).thenReturn("foo");
when(mockedList.get(anyList())).thenReturn("foo");
when(mockedList.get(any())).thenReturn("foo");

// if want to get returned value: answer
Mockito.doAnswer(new Answer() {
    @Override
    public String answer(final InvocationOnMock invocation) throws Throwable {
        List inputList = (List) invocation.getArguments()[0];
        inputList.clear();
        System.out.println("It's for test");
        return "successful";
    }
}).when(mockedList).add(input);
// or
Answer answer = new Answer() {
    @Override
    public String answer(final InvocationOnMock invocation) throws Throwable {
        List inputList = (List) invocation.getArguments()[0];
        inputList.clear();
        System.out.println("It's for test");
        return "successful";
    }
};
when(mockedList.add(input)).thenReturn(answer);

// if want to verify method is called/not called
verify(mockedList).add(input); // add is the method name
verify(mockedList, never()).add(input);

区分:
doReturn(...).when(...)when(...).thenReturn(...)
这两个stubbing的用法总体上是一样的。但是,我们总是可以用 doReturn/when来stubbing,但是有的情况我们不能when/thenReturn。比如,如果想stubbing void methods。另一个例子是use with Mockito spies, and stubbing the same method more than once.

另一方面,when/thenReturn可以,而doReturn/when不可以的是在cimpile的时候,对要返回的value进行type-checking。不过这点不是很重要。所以总的来说,推荐使用doReturn(...).when(...)


如果我们想mock几个method,保留大部分method。比如对于List,我们只想mock .size(),对于get(...), add(...)都想让instance真的使用List里面的get/add,那么我们不能用mock,而要用Spy。 Spy可以理解成局部的mock,只mock几个method。比如:

Stock stock = mock(Stock.class);
when(stock.getPrice()).thenReturn(100.00);
when(stock.getQuantity()).thenReturn(200);
when(stock.getValue()).thenCallRealMethod();

Stock stock = spy(Stock.class);
when(stock.getPrice()).thenReturn(100.00);
when(stock.getQuantity()).thenReturn(200);
// All other method call will use the real implementations

Reference

  • https://stackoverflow.com/questions/14970516/use-mockito-to-mock-some-methods-but-not-others
  • https://stackoverflow.com/questions/20353846/mockito-difference-between-doreturn-and-when

你可能感兴趣的:(Java Unit Test Tool - Mockito)