zoukankan      html  css  js  c++  java
  • 单元测试用例编写避坑指南

     

    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("{ " +
            ""updateDate": "2020-03-23 14:47:40", " +
            ""name": "业务建模说明", " +
            ""orderNum": 10000, " +
            ""updateUser": "wangxuanyi5", " +
            ""createUser": "taijian", " +
            ""showStatus": 1, " +
            ""documentContent": { " +
            ""updateDate": "2020-07-08 14:56:18", " +
            ""menuId": 253, " +
            ""updateUser": "chengtingwei", " +
            ""createUser": "taijian", " +
            ""documentStatus": 1, " +
            ""id": 254, " +
            ""content": "在充分了解前台业务现状得更快速高效。", " +
            ""createDate": "2020-03-22 16:34:13" " +
            "}, " +
            ""id": 253, " +
            ""parentId": 251, " +
            ""createDate": "2020-03-22 16:34:13" " +
            "}");
     
    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;
    }
  • 相关阅读:
    Mybatis一级缓存和二级缓存总结
    UML模型的基本概念
    Proxy patten 代理模式
    UML 基础:类图
    Java与UML交互图
    Composite Pattern (组合模式)
    用例建模指南
    Prototype Pattern(原型模式)
    Adapter Pattern(适配器模式)
    UML 类与类之间的关系
  • 原文地址:https://www.cnblogs.com/scy251147/p/15356144.html
Copyright © 2011-2022 走看看