編程過程可以抽象為expect-run-verify苛预,而在Java中我們常用單元測試來保證程序運行結果符合我們的預期。
Mockito可以實現(xiàn):
- 在得到程序輸出結果后沥邻,驗證結果是否符合預期罩润;
- 在其依賴方法還沒有編寫完成時,mock接口的執(zhí)行結果铅辞。
mock
- 通過when(...).then(...)指定具體行為動作的mock結果厌漂;
- 可通過如下方式自定義響應:
when(mock.someMethod(anyString())).thenAnswer(
new Answer() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
Object mock = invocation.getMock();
return "called with arguments: " + Arrays.toString(args);
}
});
//Following prints "called with arguments: [foo]"
System.out.println(mock.someMethod("foo"));
import static org.mockito.Mockito.*;
// 通過mock方法創(chuàng)建一個mock類,該實例的所有調用返回的都是mock值
List mockedList = mock(List.class);
// 使用mock實例斟珊,不會拋出任何非檢查型異常
mockedList.add("one");
mockedList.clear();
// 驗證某方法是否執(zhí)行過
verify(mockedList).add("one");
verify(mockedList).clear();
//定義一個stub存根苇倡,mock方法執(zhí)行返回結果
when(mockedList.get(0)).thenReturn("first");
// 命中stub,符合上面定義的mock條件囤踩,返回mock結果
System.out.println(mockedList.get(0));
// 因為get(999)未命中stub旨椒,故返回null
System.out.println(mockedList.get(999));
測試輸出結果如下:
mock測試結果
@mock
public class ArticleManagerTest extends SampleBaseTestCase {
@Mock private ArticleCalculator calculator;
@Mock(name = "database") private ArticleDatabase dbMock;
@Mock(answer = RETURNS_MOCKS) private UserProvider userProvider;
@Mock(extraInterfaces = {Queue.class, Observer.class}) private articleMonitor;
private ArticleManager manager;
@Before public void setup() {
manager = new ArticleManager(userProvider, database, calculator, articleMonitor);
}
}
public class SampleBaseTestCase {
@Before public void initMocks() {
//MockitoAnnotations.initMocks(this)必須在test執(zhí)行前調用
MockitoAnnotations.initMocks(this);
}
}
spy
- mock代理部分指定的方法,其余方法都執(zhí)行真實的方法動作堵漱。
List list = new LinkedList();
List spy = spy(list);
//可以選擇性stub部分方法综慎,其余未被代理的方法會真實執(zhí)行
when(spy.size()).thenReturn(100);
//真實調用執(zhí)行
spy.add("one");
spy.add("two");
//打印第一個元素
System.out.println(spy.get(0));
//size() 方法被mock代理了,返回設定值:100
System.out.println(spy.size());
//驗證
verify(spy).add("one");
verify(spy).add("two");
測試輸出結果如下:
spy測試結果
@spy
public class Test{
//Instance for spying is created by calling constructor explicitly:
@Spy Foo spyOnFoo = new Foo("argument");
//Instance for spying is created by mockito via reflection (only default constructors supported):
@Spy Bar spyOnBar;
@Before
public void init(){
MockitoAnnotations.initMocks(this);
}
...
}
/****************等同于*********/
Foo spyOnFoo = Mockito.spy(new Foo("argument"));
Bar spyOnBar = Mockito.spy(new Bar());
verify
- 驗證執(zhí)行方法是否被調用執(zhí)行指定的次數(shù)
List<String> mockedList = mock(List.class);
//using mock
mockedList.add("once");
mockedList.add("twice");
mockedList.add("twice");
mockedList.add("three times");
mockedList.add("three times");
mockedList.add("three times");
//following two verifications work exactly the same - times(1) is used by default
verify(mockedList).add("once");
verify(mockedList, times(1)).add("once");
//exact number of invocations verification
verify(mockedList, times(2)).add("twice");
verify(mockedList, times(3)).add("three times");
//verification using never(). never() is an alias to times(0)
verify(mockedList, never()).add("never happened");
//verification using atLeast()/atMost()
verify(mockedList, atLeastOnce()).add("three times");
verify(mockedList, atLeast(2)).add("three times");
verify(mockedList, atMost(5)).add("three times");