• 15
  • 14
分享

       今天来介绍一款工具Squaretest,它是一款自动生成单元测试的插件,为什么会用到它也是因为最近公司上了代码质量管控的指标,会考评各个项目的单元测试覆盖率,以及sonar扫描出来的各种问题,很多老项目老代码,或者着急交付的项目,单元测试严重缺失,覆盖率只有5%不到,所以几个小伙伴这几天就在疯狂的堆单元测试,3个人堆了2天才堆到30%,于是我也来上手帮忙写了两个,写到第二个的时候就发现,这个活不应该是人干的,要去看原来的代码,然后根据逻辑写各种Mock,感觉是有迹可循的东西,所以就查了下,发现果然有插件帮我们来干这个事情,那么解下来就来看看。

       我使用的是idea,我们先来下载一下插件,File——>Settings——>Plugins,搜索Squaretest,然后install就好了,插件安装完成后需要重启一下

1.png

       重启之后,菜单栏就多了一项Squaretest,下面我们来讲下怎么用,大家也可以通过看这个菜单的最后一项:Generate Test Methods(Help)来看它的一个演示,但演示不太全,我下面截图给大家看下我怎么用的,以及一些使用心得。

2.jpg

       首先我们打开一个类,这个类就是我们即将要作为实验的类,这个类有7个public方法,因为Squaretest生成的单元测试方法都是只能生成public的,当然这也是合理的嘛!毕竟private的肯定被public调用了。

3.jpg

       如果我们来手写这个类的单元测试,光看都要一会,下面看我操作,打开你的类,光标定位到代码里,右击鼠标选择Generate…

4.jpg

       然后你就会看到这里有两个熟悉的图标,第一次的话选择第二个选项,它会让你选择你一下单元测试的模板,因为我已经选择过了,所以我现在演示不回再弹出,但后面我会告诉你怎么更改模板。

5.jpg

       选择第二项后就会弹出一个框看下面这里它自动会识别出当前类需要Mock的成员变量,直接点ok

6.jpg

       自动会使用类的真实目录层次在test文件夹中创建出来一个单元测试类,类名就是原类名后加Test

7.jpg

       我把代码贴出来给大家看看它生成出来的是什么样的,看看吓不吓人,牛逼牛逼,7个单元测试方法,秒秒钟就出来了,各位看官你们自己写要多久能写出来,毕竟时间就是金钱啊!然后我们执行一把试试!

public class CrawlerScreenShotServiceImplTest {
    @Mock
    private CrawerScreenShotTaskMapper mockCrawerScreenShotTaskMapper;
    @Mock
    private CrawerScreenShotTaskLogMapper mockCrawerScreenShotTaskLogMapper;
    @InjectMocks
    private CrawlerScreenShotServiceImpl crawlerScreenShotServiceImplUnderTest;
    @Before
    public void setUp() {
        initMocks(this);
    }
    @Test
    public void testReceiveData() {
        // Setup
        final CrawlerScreenShotVO vo = new CrawlerScreenShotVO();
        vo.setUrl("url");
        vo.setPcFlag(false);
        vo.setMembergroup("membergroup");
        vo.setTaskType(0);
        vo.setUrlType(0);
        when(mockCrawerScreenShotTaskLogMapper.saveSelective(any(CrawerScreenShotTaskLog.class))).thenReturn(0);
        when(mockCrawerScreenShotTaskMapper.saveBatch(Arrays.asList(new CrawlerScreenShotTask(0L, "url", "imageOssUrl", false, false, "memberGroup", 0, 0, "fileName", new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime(), new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime(), false, "skuCode", "state", "operater")))).thenReturn(0);
        // Run the test
        final Result<String> result = crawlerScreenShotServiceImplUnderTest.receiveData(vo);
        // Verify the results
    }
    @Test
    public void testListJobScreenShotTask() {
        // Setup
        // Configure CrawerScreenShotTaskMapper.listJobScreenShotTask(...).
        final CrawlerScreenShotTaskDto crawlerScreenShotTaskDto = new CrawlerScreenShotTaskDto();
        crawlerScreenShotTaskDto.setId(0L);
        crawlerScreenShotTaskDto.setUrl("url");
        crawlerScreenShotTaskDto.setSkuCode("skuCode");
        crawlerScreenShotTaskDto.setPcFlag(false);
        crawlerScreenShotTaskDto.setMemberGroup("memberGroup");
        crawlerScreenShotTaskDto.setUrlType(0);
        crawlerScreenShotTaskDto.setFileName("fileName");
        crawlerScreenShotTaskDto.setTaskType(0);
        crawlerScreenShotTaskDto.setState("state");
        final List<CrawlerScreenShotTaskDto> crawlerScreenShotTaskDtos = Arrays.asList(crawlerScreenShotTaskDto);
        when(mockCrawerScreenShotTaskMapper.listJobScreenShotTask(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime())).thenReturn(crawlerScreenShotTaskDtos);
        // Run the test
        final List<CrawlerScreenShotTaskDto> result = crawlerScreenShotServiceImplUnderTest.listJobScreenShotTask();
        // Verify the results
    }
    @Test
    public void testQuery() {
        // Setup
        final NikeScreenShotListRequestVo requestVo = new NikeScreenShotListRequestVo();
        requestVo.setUrl("url");
        requestVo.setUrlType(0);
        requestVo.setStartTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());
        requestVo.setEndTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());
        requestVo.setStatus(0);
        requestVo.setPcFlag(0);
        requestVo.setPageNum(0);
        requestVo.setPageSize(0);
        // Configure CrawerScreenShotTaskMapper.query(...).
        final PimScreenShotVo pimScreenShotVo = new PimScreenShotVo();
        pimScreenShotVo.setId(0L);
        pimScreenShotVo.setUrl("url");
        pimScreenShotVo.setImageOssUrl("imageOssUrl");
        pimScreenShotVo.setStatus(0);
        pimScreenShotVo.setPcFlag(false);
        pimScreenShotVo.setCreateTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());
        pimScreenShotVo.setUrlType(0);
        pimScreenShotVo.setMsg("msg");
        final List<PimScreenShotVo> pimScreenShotVos = Arrays.asList(pimScreenShotVo);
        when(mockCrawerScreenShotTaskMapper.query(any(NikeScreenShotListRequestVo.class))).thenReturn(pimScreenShotVos);
        // Run the test
        final PageInfo<PimScreenShotVo> result = crawlerScreenShotServiceImplUnderTest.query(requestVo);
        // Verify the results
    }
    @Test
    public void testQuerySelectBoxData() {
        // Setup
        // Configure CrawerScreenShotTaskMapper.query(...).
        final PimScreenShotVo pimScreenShotVo = new PimScreenShotVo();
        pimScreenShotVo.setId(0L);
        pimScreenShotVo.setUrl("url");
        pimScreenShotVo.setImageOssUrl("imageOssUrl");
        pimScreenShotVo.setStatus(0);
        pimScreenShotVo.setPcFlag(false);
        pimScreenShotVo.setCreateTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());
        pimScreenShotVo.setUrlType(0);
        pimScreenShotVo.setMsg("msg");
        final List<PimScreenShotVo> pimScreenShotVos = Arrays.asList(pimScreenShotVo);
        when(mockCrawerScreenShotTaskMapper.query(any(NikeScreenShotListRequestVo.class))).thenReturn(pimScreenShotVos);
        // Run the test
        final PimScreenShotTaskParamsDto result = crawlerScreenShotServiceImplUnderTest.querySelectBoxData();
        // Verify the results
    }
    @Test
    public void testFindExecutionScreenShotTaskCount() {
        // Setup
        when(mockCrawerScreenShotTaskMapper.findExecutionScreenShotTaskCount()).thenReturn(0);
        // Run the test
        final Integer result = crawlerScreenShotServiceImplUnderTest.findExecutionScreenShotTaskCount();
        // Verify the results
        assertEquals(0, result);
    }
    @Test
    public void testFindCrawerScreenshotTaskByCreateTime() {
        // Setup
        final CrawlerScreenShotTaskSyncDto crawlerScreenShotTaskSyncDto = new CrawlerScreenShotTaskSyncDto();
        crawlerScreenShotTaskSyncDto.setId(0L);
        crawlerScreenShotTaskSyncDto.setUrl("url");
        crawlerScreenShotTaskSyncDto.setSkuCode("skuCode");
        crawlerScreenShotTaskSyncDto.setTaskType(0);
        crawlerScreenShotTaskSyncDto.setStatus(0);
        crawlerScreenShotTaskSyncDto.setLastModifyTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());
        crawlerScreenShotTaskSyncDto.setOperater("operater");
        crawlerScreenShotTaskSyncDto.setMsg("msg");
        final List<CrawlerScreenShotTaskSyncDto> expectedResult = Arrays.asList(crawlerScreenShotTaskSyncDto);
        // Configure CrawerScreenShotTaskMapper.findCrawerScreenshotTaskByCreateTime(...).
        final CrawlerScreenShotTaskSyncDto crawlerScreenShotTaskSyncDto1 = new CrawlerScreenShotTaskSyncDto();
        crawlerScreenShotTaskSyncDto1.setId(0L);
        crawlerScreenShotTaskSyncDto1.setUrl("url");
        crawlerScreenShotTaskSyncDto1.setSkuCode("skuCode");
        crawlerScreenShotTaskSyncDto1.setTaskType(0);
        crawlerScreenShotTaskSyncDto1.setStatus(0);
        crawlerScreenShotTaskSyncDto1.setLastModifyTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());
        crawlerScreenShotTaskSyncDto1.setOperater("operater");
        crawlerScreenShotTaskSyncDto1.setMsg("msg");
        final List<CrawlerScreenShotTaskSyncDto> crawlerScreenShotTaskSyncDtos = Arrays.asList(crawlerScreenShotTaskSyncDto1);
        when(mockCrawerScreenShotTaskMapper.findCrawerScreenshotTaskByCreateTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime())).thenReturn(crawlerScreenShotTaskSyncDtos);
        // Run the test
        final List<CrawlerScreenShotTaskSyncDto> result = crawlerScreenShotServiceImplUnderTest.findCrawerScreenshotTaskByCreateTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());
        // Verify the results
        assertEquals(expectedResult, result);
    }
    @Test
    public void testQueryCrawlerDashboard() {
        // Setup
        when(mockCrawerScreenShotTaskMapper.queryCrawlerDashboard(0, 0, 0, new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime(), new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime())).thenReturn(0);
        // Run the test
        final Integer result = crawlerScreenShotServiceImplUnderTest.queryCrawlerDashboard(0, 0, 0, new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime(), new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());
        // Verify the results
        assertEquals(0, result);
    }
}

       报错了呢,不要慌,这个直接干掉就可以了。

8.jpg

       怎么样!刺不刺激,爽不爽,秒秒钟90多行的代码覆盖率就到了90%以上.

9.jpg

       上面说过第一次进来会让你选择单元测试的模板,如果你要切换的话可以在单元测试类中按快捷键,Alt+M,或者通过Squaretest的菜单倒数第二个,下面这个就是按快捷键的效果,我选择的是这个模板,你们也可以借鉴。

10.jpg

       OK,以上Squaretest部分就结束了,当然拉也不能高兴的太早,这个类算是比较成功的情况,很多时候还是要你自己小修小改的,毕竟它生成出来的测试数据可能完全匹配不上你的if else数据对吧,但这都很好改啊,这样就从自己分析if else变成了,debug程序了呀,哪里报错,debug过去,看看是不是生成的数据有问题,改个数据,就通过了,反正本人用的是很舒畅的,妥妥的节省70%的工作量。

       解决了上面一个问题之后,又发现另一个问题,这个工具VO,DTO,Entity,Command,Model这种实体类来讲,一般这种实体类我们都用lombok的注解get,set,还有constract构造器等注解,但是这个工具只能生成这些实体类的构造器的单元测试,无法生成get set方法的单元测试,所以写了个base方法,实体类继承一下,简单的写两行带就好了,看下面代码:

@SpringBootTest
@RunWith(MockitoJUnitRunner.class)
public abstract class BaseVoEntityTest<T> {
    protected abstract T getT();
    private void testGetAndSet() throws IllegalAccessException, InstantiationException, IntrospectionException,
            InvocationTargetException {
        T t = getT();
        Class modelClass = t.getClass();
        Object obj = modelClass.newInstance();
        Field[] fields = modelClass.getDeclaredFields();
        for (Field f : fields) {
            boolean isStatic = Modifier.isStatic(f.getModifiers());
            // 过滤字段
            if (f.getName().equals("isSerialVersionUID") || f.getName().equals("serialVersionUID") || isStatic || f.getGenericType().toString().equals("boolean")
                    || f.isSynthetic()) {
                continue;
            }
            PropertyDescriptor pd = new PropertyDescriptor(f.getName(), modelClass);
            Method get = pd.getReadMethod();
            Method set = pd.getWriteMethod();
            set.invoke(obj, get.invoke(obj));
        }
    }
    @Test
    public void getAndSetTest() throws InvocationTargetException, IntrospectionException,
            InstantiationException, IllegalAccessException {
        this.testGetAndSet();
    }
}

       同样的方式我们在实体类上通过Squaretest生成单元测试,然后继承我上面写的那个base类,vo的单元测试代码稍加改动,如下

11.jpg

       看run完之后,覆盖率100%,妥妥的,通过这两个解决方案,一天之内我们就把覆盖率搞到了60%以上,不要太刺激,大家可以用用试试哦,当然这个也不是纯为了应付差事写的单元测试,我们后续开发的时候,也可以用这个工具来生成,然后自测自己的代码,这样也是提升工作效率的嘛!

12.jpg


作者:孙琛斌(浮生)

原文链接:https://blog.csdn.net/sun5769675/article/details/111043213#comments_14603553

  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          •   近日,#董明珠怒斥员工吃着碗里看着锅里#上了热搜。  董明珠在访谈中表示,她曾找员工来谈话,让他们去持有格力的股票,有的可能认为买这个没什么用,也许过两年就走了;有的买了,捞一把,最后还是走了。有的人吃着碗里还看着锅里的,绝对不会允许他在格力待下去。  在这个话题下,有接近10万位网友留言,不仅如此,这个采访在企业内部也引起了讨论。  作为企业高管及董事之一的CC认为,“吃着碗里的看着锅里”的员工明显是对企业的忠诚度不够,这样的员工不能留。  公司给员工的薪资福利根据员工的能力已充足,即“德配位”,职业规划也不错,员工依然“吃着碗里的看着锅里”,这样的员工“胃口”太大养不活,甚至不客气的说...
            0 0 1626
            分享
          •   今天给大家推荐一款基于Python的网页自动化工具:DrissionPage。这款工具既能控制浏览器,也能收发数据包,甚至能把两者合而为一,简单来说:集合了WEB浏览器自动化的便利性和 requests 的高效率。  一、DrissionPage产生背景  实现网页自动化,会有两类形式: - 直接向服务器发送请求数据包,获取需要的数据 - 模拟真实用户操作行为,控制浏览器跟网页进行交互  前者轻量级,速度快,例如requests 库。但requests面对需要登录的网站时,往往还要应付验证码、JS 混淆、签名参数等反爬手段,门槛较高。若数据是由 JS 计算生成的,还须重现计算过程,开发效率...
            0 0 3169
            分享
          • 本文以最常见的几种测试场景来展开讨论如何设计出更为高效且覆盖面更为全的测试用例。在讨论前,我们先来大概了解下目前行业里常用到的几种测试用例的设计方法,目前主流的测试用例设计方法有如下几种1、测试用例常用设计方法1.1 等价类划分法此设计方法算是黑盒测试中用得最多的一个了,而且此方法常常与其他方法一起来设计测试用例,常用的组合就是与边界值划分法;定义:等价类划分法是把所有可能输入的数据划分成若干部分,然后从每一个部分选取少数具有代表性的数据作为测试用例。划分标准:完整性,即被划分的各个部分测试数据共同组成了所有可能输入的数据;排他性,即每个部分的测试数据原则上来说,不应该有重叠部分。划分方法:在...
            16 16 3158
            分享
          •   1 JIRA API 简介  JIRA 在不同的企业 行业 应用的方法都是不一样的,有的需求通过JIRA配置就可以实现,有的需求无法通过配置来实现,或者基于提效的目的,就需要基于 JIRA API 进行二次开发。比如:批量导入团队成员, 批量配置项目空间,两个不同问题类型状态的关联转换等等。  JIRA官网的指导手册是基于 Java的,只有英文版的。由于我没有java基础,所以我是用的python来实现的二次开发。python的jira库,功能是完整的,官网上有接口,库里都有。  python 版:https://jira.readthedocs.io/ind...
            0 0 1361
            分享
          •   背景  性能是网站和应用的支柱,网站性能高,用户体验会更好,同时,网站速度也是搜索引擎排名的一个因素。因此,好的网站性能直接影响我们的收益指标,因此有必要提高网站的性能,从而从技术角度拿到业务收益。  性能优化的指标  RAIL模型是Google给出的一套以用户为中心的性能模型,它提供了一种考虑性能的结构。 该模型将用户体验分解为关键操作(例如,点击、滚动、加载)并帮助您为每个操作定义性能目标。 RAIL分别代表:  · Response:响应  · Animation:动画  · Idle:空闲  · Load:加载 如下图所示:  响应  在 100 毫秒...
            0 1 338
            分享
      • 51testing软件测试圈微信