Java單元測試神器之Mockito

什麼是 Mock 測試

Mock測試就是在測試過程當中,對於某些不容易構造或者不容易獲取的對象,用一個虛擬的對象來建立以便測試的測試方法。什麼是不容易構造的對象呢?例如HttpServletRequest,須要在有servlet容器環境中建立獲取。那不容易獲取的對象呢?如一個JedisCluster,須要準備redis相關環境,而後設置進去等等。html

Mock 能夠分解在單元測試中耦合的其餘類或者接口,它可以幫你模擬這些依賴,並幫你驗證所調用的依賴的行爲。java

場景事例

 

 

當咱們須要測試OrderService時,按照咱們常規的作法呢,都是要先準備好redis,跟db的環境,而後構造UserService跟CouponService注入進來,此時須要構建完整的依賴樹,其過程是比較繁瑣的,萬一數據庫連不上,依賴找不到,服務掛了... 時間一長可能會打擊咱們對項目進行單測的積極性,因此這時候頗有必要尋求一種優雅的方式來解決。web

鐺鐺鐺~這時候Mockito出現了(java中Mock框架比較多,可是本篇只介紹這個),它會把那些繁瑣的依賴通通轉化爲Mock Object,以下圖,這樣咱們就能夠專一的進行咱們的單測,減小在解決依賴上浪費的時間了。redis

 

 

直接開幹

關於Mockito的簡介這裏就不在贅述了,你們有興趣能夠自行去官方文檔查閱,這裏主要帶你們瞭解一些經常使用的Mock方法。數據庫

maven依賴bash

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>2.23.4</version>
    <scope>test</scope>
</dependency>

  

爲了代碼測試的方便,直接在測試類中靜態導入 import static org.mockito.Mockito.*;微信

基礎方法

@Test
   public void testMockBase(){
       //建立ArrayList的Mock對象
       List mockList = mock(ArrayList.class);
       //pass
       Assert.assertTrue(mockList instanceof ArrayList);

       //當咱們mockList調用方法去add("張三")的時候會返回true
       when(mockList.add("張三")).thenReturn(true);
       //當咱們mockList調用方法size()的時候返回10
       when(mockList.size()).thenReturn(10);
       //pass
       Assert.assertTrue(mockList.add("張三"));
       //pass
       Assert.assertFalse(mockList.add("李四"));
       //pass
       Assert.assertEquals(mockList.size(),10);
       //null
       System.out.println(mockList.get(0));
   }
 

mock靜態方法會建立一個Mock對象,因爲 Mock對象 並不會真的執行方法中的代碼,因此若是未指定返回值的話會返回默認值(如19行)。第9、十行咱們指定了mockList在執行特定方法後須要返回的值,因此在assertTrue校驗是沒問題的,可是add("李四"),咱們並沒設置,因此是false。app

校驗方法調用次數

//使用mock
 List mockedList = mock(ArrayList.class);
 mockedList.add("once");

 mockedList.add("twice");
 mockedList.add("twice");

 mockedList.add("three times");
 mockedList.add("three times");
 mockedList.add("three times");
 
 //這裏默認是判斷該方法調用times(1),同下
 verify(mockedList).add("once");
 verify(mockedList, times(1)).add("once");

 verify(mockedList, times(2)).add("twice");
 verify(mockedList, times(3)).add("three times");
 //從沒調用,times(0)
 verify(mockedList, never()).add("never happened");
 //最少一次,最少幾回,最多幾回
 verify(mockedList, atLeastOnce()).add("three times");
 verify(mockedList, atLeast(2)).add("three times");
 verify(mockedList, atMost(5)).add("three times");
 

其實在上述的代碼中,命名是比較直觀的,因此我這邊就直接註釋在代碼中了。框架

校驗方法調用時長

//方法執行在100ms之內的時候能夠經過
   verify(mock, timeout(100)).someMethod();
   //同上
   verify(mock, timeout(100).times(1)).someMethod();

   //方法2次調用均沒超過100ms
   verify(mock, timeout(100).times(2)).someMethod();

   verify(mock, timeout(100).atLeast(2)).someMethod();

 

 

經過超時檢測能夠校驗咱們的方法邏輯會不會有出現問題而致使超時的地方。maven

參數匹配

linkedList.add("element");
// anyInt() 任何整數咱們都返回 element 
when(linkedList.get(anyInt())).thenReturn("element");

System.out.print(linkedList.get(10));//返回element

 

方法拋出異常

 @Test(expected = RuntimeException.class)
    public void doThrow(){
        List list = mock(List.class);
        doThrow(new RuntimeException()).when(list).add(1);
        list.add(1);
    }

 

使用註解注入

  public class ArticleManagerTest {

       @Mock private ArticleCalculator calculator;
       @Mock private ArticleDatabase database;
       @Mock private UserProvider userProvider;

       private ArticleManager manager;
 

要注意的是,經過註解的方式用使用的話,咱們必須在添加初始化mock的代碼,否則即便標註了註解也會是null

MockitoAnnotations.initMocks(testClass);

 

關於Mockito更多詳細的用法,你們能夠直接參考官方文檔,由於各類「奇技淫巧」確實比較多,後面也更新對java8 lambda的支持,不少功能仍是期待你們去挖掘~

 

 

更多詳細用法可直接參考官方文檔:

static.javadoc.io/org.mockito…

相信當你熟練使用Mockito之後,你會愛上寫單測的,也會讓你代碼健壯性有所增強。有些bug能提早發現的話,總比運行的時候被別人半夜叫起來修復舒服是吧?

 

 

微信公衆號《深夜裏的程序猿》 -  天天分享最乾的乾貨
相關文章
相關標籤/搜索