單元測試用例編寫避坑指南

 

1.入口方法如何查找mock調用鏈

寫單測用例的時候,需要對入口方法涉及的各種實例進行mock,諸如數據庫操作,redis操作,rpc訪問等等,至於純內存計算的實例,只要是條件ok,則可以不必進行mock。

進行mock的時候,有些實例調用有可能隱藏的很深,假設我們沒有發現,有可能造成單測用例執行失敗,這就需要我們debug待測方法,列出需要進行mock的實例,然後一一操作即可。

單測用例生成框架, tiny-autounit,則是通過遞歸走查方法體,然後找到相關實例並進行mock,節省大量的查找時間。

 

2. 對ElasticSearch進行mock

系統中,如果用了es,且摻雜有比較複雜的邏輯,則需要對es進行mock,整體mock方式如下:

SearchResponse進行mock: 

SearchResponse searchResponse = mock(SearchResponse.class);
 
 
SearchHits searchHits = mock(SearchHits.class);
when(searchResponse.getHits()).thenReturn(searchHits);
 
 
SearchHit[] searchHits1 = new SearchHit[1];
searchHits1[0] = mock(SearchHit.class);
when(searchResponse.getHits().getHits()).thenReturn(searchHits1);
 
 
when(searchHits1[0].getSourceAsString()).thenReturn("{\n" +
        "\"updateDate\": \"2020-03-23 14:47:40\",\n" +
        "\"name\": \"業務建模說明\",\n" +
        "\"orderNum\": 10000,\n" +
        "\"updateUser\": \"wangxuanyi5\",\n" +
        "\"createUser\": \"taijian\",\n" +
        "\"showStatus\": 1,\n" +
        "\"documentContent\": {\n" +
        "\"updateDate\": \"2020-07-08 14:56:18\",\n" +
        "\"menuId\": 253,\n" +
        "\"updateUser\": \"chengtingwei\",\n" +
        "\"createUser\": \"taijian\",\n" +
        "\"documentStatus\": 1,\n" +
        "\"id\": 254,\n" +
        "\"content\": \"在充分了解前臺業務現狀得更快速高效。\",\n" +
        "\"createDate\": \"2020-03-22 16:34:13\"\n" +
        "},\n" +
        "\"id\": 253,\n" +
        "\"parentId\": 251,\n" +
        "\"createDate\": \"2020-03-22 16:34:13\"\n" +
        "}");
 
TotalHits totalHits = new TotalHits(10, TotalHits.Relation.EQUAL_TO);
when(searchResponse.getHits().getTotalHits()).thenReturn(totalHits);
 
when(elasticsearchNativeOperation.search(Mockito.any(), Mockito.anyString())).thenReturn(searchResponse);

UpdateResponse進行mock:

UpdateResponse updateResponse = mock(UpdateResponse.class);

BulkByScrollResponse進行mock:

BulkByScrollResponse bulkByScrollResponse = mock(BulkByScrollResponse.class);

 

3. 對static類進行mock

注意,@BeforeClass和@AfterClass要成對出現。

@BeforeClass
public static void beforeClass(){
   authorityUtilMockedStatic = Mockito.mockStatic(AuthorityUtil.class);
}
 
@AfterClass
public static void afterClass(){
   authorityUtilMockedStatic.close();
}
 
private static MockedStatic<AuthorityUtil> authorityUtilMockedStatic ;
 
@Test
public void when_list_then_return_success1(){
   authorityUtilMockedStatic.when(()->AuthorityUtil.getUserErp()).thenReturn("test");
   authorityUtilMockedStatic.when(()->AuthorityUtil.isPdAdmin()).thenReturn(false);
   //todo biz
   List returnResult = pdProductInfoServiceImpl.list();
   assert returnResult != null;
}

 

4. 對入參類型進行mock過程中的注意事項

如果入參是自定義的類對象,則需要利用Mockito.any()來進行,也可以自己new出來一個新類來進行:

when(elasticsearchNativeOperation.search(Mockito.any())).thenReturn(searchResponse);

如果入參既有自定義類對象,也有元數據類型,則可以用如下方式:

when(elasticsearchNativeOperation.search(Mockito.any(), Mockito.anyString())).thenReturn(searchResponse);
或者
when(elasticsearchNativeOperation.search(Mockito.any(), eq("testSring"))).thenReturn(searchResponse);

千萬要注意的是,一旦參數中,有一個參數你用了Mockito.***,那麼其他參數你要麼用Mockito.***來替代, 要麼用eq(***具體的參數值***)來替代,不允許直接輸入參數值。

如果入參是Integer,但是你用了Mockito.any()來替代,大概率會出現nullpointer錯誤,這點需要注意,一定要用對替代類型。

 

5. 實例返回結果爲null

經常我們在打好mock樁之後,debug代碼中後,發現返回的結果爲null,怎麼設置參數都不行。實際上這種情況,是因爲你入參中有參數爲null造成的,此時,你需要將爲null的參數給處理爲非null的數據即可。

如果null參數數據比較難處理,你也可以在打樁的地方,直接給對應的參數設置爲 eq(null) 也可以,這樣實例返回結果就會返回你的打樁值了。

 

6. 單測方法一對多

一般一個業務方法是對用多個單測方法的,因爲有些分支條件,需要多個單測方法才能覆蓋完畢,所以不要吝嗇多寫單測方法,即便重複了,也沒事兒。

 

7. Exception異常類處理

異常類的話,一般在方法頭上打,不必自己進行捕獲,利用expected關鍵字即可。

@Test(expected = ComponentBusinessException.class)
public void when_addAppComponent_then_appname_null() {
    when(lockService.lock(eq(LockEnums.LockTypeEnums.REDIS), Mockito.anyString(), Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt())).thenReturn(false);
    Component4AddAppEntity entity = new Component4AddAppEntity();
    entity.setCurrentLimitLevel("test");
    entity.setDeptName("test");
    ComponentInfoEntity returnResult = componentServiceImpl.addAppComponent(entity);
    assert returnResult != null;
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章