一款自动生成单元测试的 IDEA 插件
Hollis的新书限时折扣中,一本深入讲解Java基础的干货笔记!
今天来介绍一款工具Squaretest,它是一款自动生成单元测试的插件,为什么会用到它?
主要因为最近公司上了代码质量管控的指标,会考评各个项目的单元测试覆盖率,以及sonar扫描出来的各种问题,很多老项目老代码,或者着急交付的项目,单元测试严重缺失,覆盖率只有5%不到。
所以几个小伙伴这几天就在疯狂的堆单元测试,3个人堆了2天才堆到30%,于是我也来上手帮忙写了两个,写到第二个的时候就发现,这个活不应该是人干的,要去看原来的代码,然后根据逻辑写各种Mock,感觉是有迹可循的东西,所以就查了下,发现果然有插件帮我们来干这个事情,那么解下来就来看看。
我使用的是idea,我们先来下载一下插件,File——>Settings——>Plugins
,搜索Squaretest
,然后install
就好了,插件安装完成后需要重启一下
重启之后,菜单栏就多了一项Squaretest
,下面我们来讲下怎么用,大家也可以通过看这个菜单的最后一项:Generate Test Methods(Help)
来看它的一个演示,但演示不太全,我下面截图给大家看下我怎么用的,以及一些使用心得。
首先我们打开一个类,这个类就是我们即将要作为实验的类,这个类有7个public方法,因为Squaretest
生成的单元测试方法都是只能生成public的,当然这也是合理的嘛!毕竟private的肯定被public调用了。
如果我们来手写这个类的单元测试,光看都要一会,下面看我操作,打开你的类,光标定位到代码里,右击鼠标选择Generate…
然后你就会看到这里有两个熟悉的图标,第一次的话选择第二个选项,它会让你选择你一下单元测试的模板,因为我已经选择过了,所以我现在演示不回再弹出,但后面我会告诉你怎么更改模板。
选择第二项后就会弹出一个框看下面这里它自动会识别出当前类需要mock的成员变量,直接点ok
自动会使用类的真实目录层次在test文件夹中创建出来一个单元测试类,类名就是原类名后加Test
我把代码贴出来给大家看看它生成出来的是什么样的,看看吓不吓人,牛逼牛逼,7个单元测试方法,秒秒钟就出来了,各位看官你们自己写要多久能写出来,毕竟时间就是金钱啊!然后我们执行一把试试!
public class CrawlerScreenShotServiceImplTest {@Mockprivate CrawerScreenShotTaskMapper mockCrawerScreenShotTaskMapper;@Mockprivate CrawerScreenShotTaskLogMapper mockCrawerScreenShotTaskLogMapper;@InjectMocksprivate CrawlerScreenShotServiceImpl crawlerScreenShotServiceImplUnderTest;@Beforepublic void setUp() {initMocks(this);}@Testpublic void testReceiveData() {// Setupfinal 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 testfinal Result<String> result = crawlerScreenShotServiceImplUnderTest.receiveData(vo);// Verify the results}@Testpublic 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 testfinal List<CrawlerScreenShotTaskDto> result = crawlerScreenShotServiceImplUnderTest.listJobScreenShotTask();// Verify the results}@Testpublic void testQuery() {// Setupfinal 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 testfinal PageInfo<PimScreenShotVo> result = crawlerScreenShotServiceImplUnderTest.query(requestVo);// Verify the results}@Testpublic 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 testfinal PimScreenShotTaskParamsDto result = crawlerScreenShotServiceImplUnderTest.querySelectBoxData();// Verify the results}@Testpublic void testFindExecutionScreenShotTaskCount() {// Setupwhen(mockCrawerScreenShotTaskMapper.findExecutionScreenShotTaskCount()).thenReturn(0);// Run the testfinal Integer result = crawlerScreenShotServiceImplUnderTest.findExecutionScreenShotTaskCount();// Verify the resultsassertEquals(0, result);}@Testpublic void testFindCrawerScreenshotTaskByCreateTime() {// Setupfinal 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 testfinal List<CrawlerScreenShotTaskSyncDto> result = crawlerScreenShotServiceImplUnderTest.findCrawerScreenshotTaskByCreateTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());// Verify the resultsassertEquals(expectedResult, result);}@Testpublic void testQueryCrawlerDashboard() {// Setupwhen(mockCrawerScreenShotTaskMapper.queryCrawlerDashboard(0, 0, 0, new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime(), new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime())).thenReturn(0);// Run the testfinal Integer result = crawlerScreenShotServiceImplUnderTest.queryCrawlerDashboard(0, 0, 0, new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime(), new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());// Verify the resultsassertEquals(0, result);}
}
报错了呢,不要慌,这个断言是为了检查你单元测试跑出来的结果是否符合预期的,如果你不想检查只想完成覆盖率,直接干掉就可以了(手动狗头)。
怎么样!刺不刺激,爽不爽,秒秒钟90多行的代码覆盖率就到了90%以上.
上面说过第一次进来会让你选择单元测试的模板,如果你要切换的话可以在单元测试类中按快捷键,Alt+M,或者通过Squaretest
的菜单倒数第二个,下面这个就是按快捷键的效果,我选择的是这个模板,你们也可以借鉴。
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));}}@Testpublic void getAndSetTest() throws InvocationTargetException, IntrospectionException,InstantiationException, IllegalAccessException {this.testGetAndSet();}}
同样的方式我们在实体类上通过Squaretest
生成单元测试,然后继承我上面写的那个base类,vo的单元测试代码稍加改动,如下
看run完之后,覆盖率100%,妥妥的,通过这两个解决方案,一天之内我们就把覆盖率搞到了60%以上,不要太刺激,大家可以用用试试哦,当然这个也不是纯为了应付差事写的单元测试,我们后续开发的时候,也可以用这个工具来生成,然后自测自己的代码,这样也是提升工作效率的嘛!
来源:blog.csdn.net/sun5769675/article/details/111043213
完
往期推荐
痛快!SpringBoot终于禁掉了循环依赖!
最近互联网大厂都在裁员?对普通程序员有什么启示?
你管这破玩意儿叫 MQ?
有道无术,术可成;有术无道,止于术
欢迎大家关注Java之道公众号
好文章,我在看❤️
一款自动生成单元测试的 IDEA 插件相关推荐
- 懒人神器:自动生成单元测试插件 Squaretest
你是否常常因代码需编写单元测试而痛苦不堪,你是否因单元测试历史债而惆怅不断,Squaretest或许能帮你消除痛苦消除惆怅 前言 一.Squaretest是什么? 二.使用步骤 1.引入插件 2.使用 ...
- jeecg-boot自动生成代码_一款自动生成唯一头像的开源代码库
很多网站会给默认登陆的用户生成默认的头像,包括 GitHub 其实就有,你想知道是怎么实现的么? 今天的推荐的就是一个能够按唯一 Email.ID 或者用户名生成唯一头像的开源代码库:generate ...
- IDEA插件-----Squaretest(自动生成单元测试)
菜单栏就多了一项Squaretest 首先我们打开一个类,这个类就是我们即将要作为实验的类,这个类有7个public方法,因为Squaretest生成的单元测试方法都是只能生成public的,当然这也 ...
- IDEA-Java自动生成单元测试
最近在写单元测试,感觉写Mock写烦了,于是想看看有没有现成的spring项目的单元测试生成工具. 网上找到了一个Java单元测试回答的集合:Automatic generation of unit ...
- 推荐一款自动生成财务报表分析的软件
财务报表能够清晰的反映一个企业的经营状况,通过三大财务报表的资产负债表.利润表.现金流量表,能够清晰的揭示企业经营中存在的问题,也是税务局要求企业报税的必备财务报表.但是,会计手工编制财务报表,费时费 ...
- android studio 自动生成sql语句,Android Studio Plugin 插件开发教程(三) —— 制作一个自动生成数据库代码的插件...
项目源码 系列教程 插件介绍 本篇实战撸个自动生成安卓Sqlite数据库代码的插件,先演示下最终效果 db文件夹下的都是插件自动生成的,而MainActivity里面的代码是我提前写好的,用于实验插件 ...
- mybatis代码自动生成工具之maven插件mybatis-generator-maven-plugin(mybatis逆向工程)
mybatis自动代码生成工具maven插件可以帮助我们轻松的生成pojo.dao.mapper.xml文件,相比于mybatis-generator等其他方式方便许多,话不多说,上代码 先看一下整体 ...
- 黑科技:进阶必备,推荐两款自动生成代码神器
关注上方"测试开发技术",选择星标, 干货技术,第一时间送达! 最近两年,在互联网行业各大技术峰会上,都能看到关于工程效能这个概念,从侧面也反映出了研发效能已经逐渐被各企业所重视! ...
- 两款自动检测代码工具与插件,开源真香
大家好,我是TJ 一个励志推荐10000款开源项目与工具的程序员 写完代码最麻烦的是什么?就是运行时出现bug再回头去改去修,如果有一款检测工具,能自动检测出代码中是否存在bug是不是对开发者来说,更 ...
最新文章
- 在SQL Server中保存和输出任意类型的文件
- Android开发--Spinner控件的使用
- html 表单自动数值,web前端学习技术之对HTML5 智能表单的理解
- leetcode算法题--两数之和
- 在iframe框架中全屏不好使的原因
- 使用bootstrap标签页
- SAP CRM产品主数据应用里value node和model node的转换
- [导入]【翻译】WF从入门到精通(第十章):事件活动
- OpenCV_04 几何变换:图像缩放+图像平移+图像旋转+仿射变换+透射变换+图像金字塔
- jquery操作select - 代码合集
- Asp.Net MVC 3【Filters(过滤器)】
- swagger 基础入门
- 12f的接线 esp8266_ESP8266固件升级方法(ESP8266-12F模组)
- 三大知名PHP开源多用户商城系统对比
- 软件定义汽车下的整车开发
- 拔丝芋头的Java学习日记--Day4
- 华为认证的含金量高吗?
- mysql concat 长度限制_mysql中group_concat()长度限制
- dwz ajax提交,DWZ-JUI Ajax.post 封装
- dockers移盘挂载