热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Squaretest:自动生成功能测试代码的高效插件

本文将介绍一款名为Squaretest的高效插件,该工具能够自动生成功能测试代码。使用这款插件的主要原因是公司近期加强了代码质量的管控,对各项目进行了严格的单元测试评估。Squaretest不仅提高了测试代码的生成效率,还显著提升了代码的质量和可靠性。

今天来介绍一款工具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 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 crawlerScreenShotTaskDtos = Arrays.asList(crawlerScreenShotTaskDto);when(mockCrawerScreenShotTaskMapper.listJobScreenShotTask(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime())).thenReturn(crawlerScreenShotTaskDtos);// Run the testfinal List 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

 pimScreenShotVos = Arrays.asList(pimScreenShotVo);when(mockCrawerScreenShotTaskMapper.query(any(NikeScreenShotListRequestVo.class))).thenReturn(pimScreenShotVos);// Run the testfinal PageInfo

 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

 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 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 crawlerScreenShotTaskSyncDtos = Arrays.asList(crawlerScreenShotTaskSyncDto1);when(mockCrawerScreenShotTaskMapper.findCrawerScreenshotTaskByCreateTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime())).thenReturn(crawlerScreenShotTaskSyncDtos);// Run the testfinal List 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 {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


推荐阅读
  • 尽管我们尽最大努力,任何软件开发过程中都难免会出现缺陷。为了更有效地提升对支持部门的协助与支撑,本文探讨了多种策略和最佳实践,旨在通过改进沟通、增强培训和支持流程来减少这些缺陷的影响,并提高整体服务质量和客户满意度。 ... [详细]
  • 本文探讨了 Java 中 Pair 类的历史与现状。虽然 Java 标准库中没有内置的 Pair 类,但社区和第三方库提供了多种实现方式,如 Apache Commons 的 Pair 类和 JavaFX 的 javafx.util.Pair 类。这些实现为需要处理成对数据的开发者提供了便利。此外,文章还讨论了为何标准库未包含 Pair 类的原因,以及在现代 Java 开发中使用 Pair 类的最佳实践。 ... [详细]
  • Python内置模块详解:正则表达式re模块的应用与解析
    正则表达式是一种强大的文本处理工具,通过特定的字符序列来定义搜索模式。本文详细介绍了Python内置的`re`模块,探讨了其在字符串匹配、验证和提取中的应用。例如,可以通过正则表达式验证电子邮件地址、电话号码、QQ号、密码、URL和IP地址等。此外,文章还深入解析了`re`模块的各种函数和方法,提供了丰富的示例代码,帮助读者更好地理解和使用这一工具。 ... [详细]
  • Python进阶笔记:深入理解装饰器、生成器与迭代器的应用
    本文深入探讨了Python中的装饰器、生成器和迭代器的应用。装饰器本质上是一个函数,用于在不修改原函数代码和调用方式的前提下为其添加额外功能。实现装饰器需要掌握闭包、高阶函数等基础知识。生成器通过 `yield` 语句提供了一种高效生成和处理大量数据的方法,而迭代器则是一种可以逐个访问集合中元素的对象。文章详细解析了这些概念的原理和实际应用案例,帮助读者更好地理解和使用这些高级特性。 ... [详细]
  • 第六章:枚举类型与switch结构的应用分析
    第六章深入探讨了枚举类型与 `switch` 结构在编程中的应用。枚举类型(`enum`)是一种将一组相关常量组织在一起的数据类型,广泛存在于多种编程语言中。例如,在 Cocoa 框架中,处理文本对齐时常用 `NSTextAlignment` 枚举来表示不同的对齐方式。通过结合 `switch` 结构,可以更清晰、高效地实现基于枚举值的逻辑分支,提高代码的可读性和维护性。 ... [详细]
  • ButterKnife 是一款用于 Android 开发的注解库,主要用于简化视图和事件绑定。本文详细介绍了 ButterKnife 的基础用法,包括如何通过注解实现字段和方法的绑定,以及在实际项目中的应用示例。此外,文章还提到了截至 2016 年 4 月 29 日,ButterKnife 的最新版本为 8.0.1,为开发者提供了最新的功能和性能优化。 ... [详细]
  • Spring框架的核心组件与架构解析 ... [详细]
  • Netty框架中运用Protobuf实现高效通信协议
    在Netty框架中,通过引入Protobuf来实现高效的通信协议。为了使用Protobuf,需要先准备好环境,包括下载并安装Protobuf的代码生成器`protoc`以及相应的源码包。具体资源可从官方下载页面获取,确保版本兼容性以充分发挥其性能优势。此外,配置好开发环境后,可以通过定义`.proto`文件来自动生成Java类,从而简化数据序列化和反序列化的操作,提高通信效率。 ... [详细]
  • Python 中 json.dumps() 和 json.loads() 的使用方法详解——Python 面试与 JavaScript 面试必备知识
    在 Python 中,`json.dumps()` 和 `json.loads()` 是处理 JSON 数据的核心函数。`json.dumps()` 用于将字典或其他可序列化对象转换为 JSON 格式的字符串,而 `json.loads()` 则用于将 JSON 字符串解析为 Python 对象。本文详细介绍了这两个函数的使用方法及其在 Python 和 JavaScript 面试中的重要性,帮助读者掌握这些关键技能。 ... [详细]
  • 本指南从零开始介绍Scala编程语言的基础知识,重点讲解了Scala解释器REPL(读取-求值-打印-循环)的使用方法。REPL是Scala开发中的重要工具,能够帮助初学者快速理解和实践Scala的基本语法和特性。通过详细的示例和练习,读者将能够熟练掌握Scala的基础概念和编程技巧。 ... [详细]
  • 本文探讨了如何利用 jQuery 的 JSONP 技术实现跨域调用外部 Web 服务。通过详细解析 JSONP 的工作原理及其在 jQuery 中的应用,本文提供了实用的代码示例和最佳实践,帮助开发者解决跨域请求中的常见问题。 ... [详细]
  • SSAS入门指南:基础知识与核心概念解析
    ### SSAS入门指南:基础知识与核心概念解析Analysis Services 是一种专为决策支持和商业智能(BI)解决方案设计的数据引擎。该引擎能够为报告和客户端应用提供高效的分析数据,并支持在多维数据模型中构建高性能的分析应用。通过其强大的数据处理能力和灵活的数据建模功能,Analysis Services 成为了现代 BI 系统的重要组成部分。 ... [详细]
  • 本文探讨了 Kafka 集群的高效部署与优化策略。首先介绍了 Kafka 的下载与安装步骤,包括从官方网站获取最新版本的压缩包并进行解压。随后详细讨论了集群配置的最佳实践,涵盖节点选择、网络优化和性能调优等方面,旨在提升系统的稳定性和处理能力。此外,还提供了常见的故障排查方法和监控方案,帮助运维人员更好地管理和维护 Kafka 集群。 ... [详细]
  • 本文详细探讨了MySQL数据库实例化参数的优化方法及其在实例查询中的应用。通过具体的源代码示例,介绍了如何高效地配置和查询MySQL实例,为开发者提供了有价值的参考和实践指导。 ... [详细]
  • 在前文探讨了Spring如何为特定的bean选择合适的通知器后,本文将进一步深入分析Spring AOP框架中代理对象的生成机制。具体而言,我们将详细解析如何通过代理技术将通知器(Advisor)中包含的通知(Advice)应用到目标bean上,以实现切面编程的核心功能。 ... [详细]
author-avatar
vuvhvuvh
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有