5分鐘瞭解Mockito
先來看看下面這個示例:
從上圖可以看出如果我們要對A進行測試,那麼就要先把整個依賴樹構建出來,也就是BCDE的例項。
一種替代方案就是使用mocks
從圖中可以清晰的看出
mock物件就是在除錯期間用來作為真實物件的替代品。
mock測試就是在測試過程中,對那些不容易構建的物件用一個虛擬物件來代替測試的方法就叫mock測試。
知道什麼是mock測試後,那麼我們就來認識一下mock框架---Mockito
二、什麼是Mockito
除了有一個好記的名字外,Mockito嘗試用不一樣的方法做mocking測試,是簡單輕量級能夠替代EasyMock的框架。使用簡單,測試程式碼可讀性高,豐富的文件包含在javadoc中,直接在IDE中可檢視文件,例項,說明。更多資訊:
三、Stub和Mock
相同點:Stub和Mock物件都是用來模擬外部依賴,使我們能控制。
不同點:而stub完全是模擬一個外部依賴,用來提供測試時所需要的測試資料。而mock物件用來判斷測試是否能通過,也就是用來驗證測試中依賴物件間的互動能否達到預期。在mocking框架中mock物件可以同時作為stub和mock物件使用,兩者並沒有嚴格區別。 更多資訊:http://martinfowler.com/articles/mocksArentStubs.html
四、mockito入門例項
Maven依賴:(沒用maven管理的可以下載相關jar包匯入classpath)
- <dependencies>
- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-all</artifactId>
- <version>1.8.5</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
- importstatic org.mockito.Mockito.*;
- import
- import org.junit.Assert;
- import org.junit.Test;
- /**
- *
- * @author lzjun
- * @version 0.1
- * @date 2012-5-5
- * {@link http://weibo.com/u/1697702241}
- *
- */
- publicclass SimpleTest {
- @Test
- publicvoid simpleTest(){
- //建立mock物件,引數可以是類,也可以是介面
- List<String> list = mock(List.class);
- //設定方法的預期返回值
- when(list.get(0)).thenReturn("helloworld");
- String result = list.get(0);
- //驗證方法呼叫(是否呼叫了get(0))
- verify(list).get(0);
- //junit測試
- Assert.assertEquals("helloworld", result);
- }
- }
好了,五分鐘差不多了,還想繼續瞭解那就可以往下面看
建立mock物件不能對final,Anonymous ,primitive類進行mock。
可對方法設定返回異常
Java程式碼- when(list.get(1)).thenThrow(new RuntimeException("test excpetion"));
stubbing另一種語法(設定預期值的方法),可讀性不如前者
Java程式碼- doReturn("secondhello").when(list).get(1);
沒有返回值的void方法與其設定(支援迭代風格,第一次呼叫donothing,第二次dothrow丟擲runtime異常)
Java程式碼- doNothing().doThrow(new RuntimeException("void exception")).when(list).clear();
- list.clear();
- list.clear();
- verify(list,times(2)).clear();
五、引數匹配器(Argument Matcher)
Matchers類內加你有很多引數匹配器 anyInt、anyString、anyMap.....Mockito類繼承於Matchers,Stubbing時使用內建引數匹配器,下例:
Java程式碼- @Test
- publicvoid argumentMatcherTest(){
- List<String> list = mock(List.class);
- when(list.get(anyInt())).thenReturn("hello","world");
- String result = list.get(0)+list.get(1);
- verify(list,times(2)).get(anyInt());
- Assert.assertEquals("helloworld", result);
- }
需要注意的是:如果使用引數匹配器,那麼所有的引數都要使用引數匹配器,不管是stubbing還是verify的時候都一樣。
Java程式碼- @Test
- publicvoid argumentMatcherTest2(){
- Map<Integer,String> map = mock(Map.class);
- when(map.put(anyInt(),anyString())).thenReturn("hello");//anyString()替換成"hello"就會報錯
- map.put(1, "world");
- verify(map).put(eq(1), eq("world")); //eq("world")替換成"world"也會報錯
- }
六、方法呼叫的驗證(具體的呼叫次數、至少一次,一次也沒有)
Java程式碼- @Test
- publicvoid verifyInvocate(){
- 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");
- /**
- * 基本的驗證方法
- * verify方法驗證mock物件是否有沒有呼叫mockedList.add("once")方法
- * 不關心其是否有返回值,如果沒有呼叫測試失敗。
- */
- verify(mockedList).add("once");
- verify(mockedList, times(1)).add("once");//預設呼叫一次,times(1)可以省略
- verify(mockedList, times(2)).add("twice");
- verify(mockedList, times(3)).add("three times");
- //never()等同於time(0),一次也沒有呼叫
- verify(mockedList, times(0)).add("never happened");
- //atLeastOnece/atLeast()/atMost()
- verify(mockedList, atLeastOnce()).add("three times");
- verify(mockedList, atLeast(2)).add("twice");
- verify(mockedList, atMost(5)).add("three times");
- }
一次寫不完,慢慢分析。。。
參考: