干货|简单重构,显著效果-提升scala自动化测试效率之道
Posted 中兴开发者社区
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了干货|简单重构,显著效果-提升scala自动化测试效率之道相关的知识,希望对你有一定的参考价值。
每天读一篇一线开发者原创好文
▍作者简介
作者王继宏是无线通讯协议专家,团队敏捷SM,近年致力于边缘应用计算领域,在质量、效率、度量、新技术方面持续探索和改进,曾获2016年公司质量先进个人,团队两次获得中心十佳团队。
▍如何提升Scala 测试效率
一 为何提高?
敏捷对于单元测试和集成测试的自动化运行效率要求很高,期望在短时间里完成代码提交后的用例运行。常常会存在这种情况,代码运行时间很短,但是自动化用例耗时很长,一个用例执行可能不到一秒钟,但是在自动化中可能要超过好几秒,整个自动化效率低下,这是自动化测试中常见的场景。
本文结合项目实际,谈谈如何提高测试效率。
先看下我们的数据:
190个用例,CI在性能好的机器上运行花费时间8分半(512s),而在同台机器上scala统计只有26s,差距巨大。在性能不好的机器上运行CI测试需要20分钟,这效率无法满足敏捷开发。
为了提升效率,通过大量的分析和代码重构,使得最终的效率提升将近11倍,以前8分半左右的CI用例执行时间,重构后不到1分钟即可运行完毕
二.如何提高?
软件上,提升测试效率可以从以下几方面进行考虑:
1.测试系统启动效率
2.用例组合运行效率
3.单步骤用例执行效率
4.并行运行用例
下面重点讲述如何重构测试用例代码来提升效率
为了减少文章的篇幅,下文代码以一个简单的测试类来说明,相关的运行时长也是简单类的运行时长,在实际项目中,各步骤的运行时长比例子更长。如创表操作平均在2.5s
1.)测试系统启动效率
测试系统或被测对象有时需要启动一些所需的服务器,此时,可以采取mock的方式,或者整体启动一次(见下)。
2.)用例组合运行效率
整体用例运行效率和用例的编写有很大关系,例如,目前的用例大多如下编写
单个测试class实现方式:
其中:
StoragePrepare :每个it运行前连接数据库,运行后如果表存在则整个删除,同时记录也被删除
TablesDBServicePrepare:数据准备,包括创建数据表,以及插入基础表数据
整体运行过程如下,(以创5个简单的表为例,数字为运行平均时长,单位ms)
问题在哪?
1.) 一个测试集下,测试前后的动作有通用部分,需要在suite间、suite内、it内进行提炼。
以上的测试方式,将创建表和插数据混在一起作为每个it的操作,导致it操作每次都进行启动服务,连接数据库、创表动作,降低了用例执行效率,同时在代码结构上也不清晰。创建表应该是suite一次性动作,用beforeAll来实现。
2)it测试单独测试和多个it测试串行测试时,满足童子军军规,以减少相互影响。
上述运行采用里简单粗暴的方式,it只能在表的层次上删除整个表,无法采用清除记录,其原因正是beforeEach中的表和记录同时操作。
3)在领域层次方面的划分比较混乱,如果多个it测试要求的数据完全相同,可以进行子suite的拆分。
改造后,连接服务器、创表、表记录初始化、删除表都作为独立trait,在suite和it层次上进行合理调用。执行流程如下
重构后代码
这样优化后,大量的减少了重复操作,单测试class的重构基本完成。
那么,对于一个project,多个测试类怎么处理呢?我们需要继续优化下去。
同样的思想,在不同文件(class suites)共用前置操作和后置操作。
通过Suites(new UsergroupActorTest, new UsersCfgActorTest)将几个测试类整合到一个测试类中,有两种实现,
1 .)类
我们来看看gradle运行结果:
NestSuiteTest.NestSuiteTest NestSuiteTest.NestSuiteTest$$anon$1.UsergroupActorTest handleUserGroupPostRecord STANDARD_OUT
NestSuiteTest.NestSuiteTest NestSuiteTest.NestSuiteTest$$anon$2.UsersCfgActorTest handleuserpostrecord STANDARD_OUT
ActorTest.usersManage.UsersCfgActorTest UsersCfgActorTest handleuserpostrecord STANDARD_OUT
ActorTest.usersManage.UsergroupActorTest UsergroupActorTest handleUserGroupPostRecord STANDARD_OUT
发现了吗,UsergroupActorTest,UsersCfgActorTest都运行了两遍。这下晕菜了,这个咋办?
好吧,换种写法
2.)抽象类
我们再来看看gradle运行结果:
NestSuiteTest.NestSuiteTest NestSuiteTest.NestSuiteTest$$anon$1.UsergroupActorTest handleUserGroupPostRecord STANDARD_OUT
NestSuiteTest.NestSuiteTest NestSuiteTest.NestSuiteTest$$anon$2.UsersCfgActorTest handleuserpostrecord STANDARD_OUT
执行结果显示,只执行了一遍,但是,IDEA中单独执行UsergroupActorTest也成了泡影,因为abstract class UsergroupActorTest,你懂的。
这也是条死路啊,由此牵扯出另外一个问题,如何执行指定测试类?
如何执行指定测试类
注:如果你知道,可以果断跳过
先看看gradle的帮助,gradle help —task :test 查看任务test的帮助,
帮助会告诉 —tests Sets test class or method name to be included, ‘*’ is supported.
网上一边倒的说用这个参数可以运行单个测试类
但是,但是,这个是个大馅饼啊
在非SBT方式安装的scala下,这个写法完全无效,依然是所有的suite玩命地运行,而码农们只能苦苦等待。不靠谱的帮助。没招,只好转投IDEA,
在IntelliJ IDEA中运行用例的方式(gradle没配置junit)
如果用例编写采用@RunWith(classOf[JUnitRunner]),则可以选择在gradle、Junit或scalatest下运行,并在IntelliJ IDEAJunit下自动添加配置,后续默认以第一次选择的方式执行,直到手工删除该配置。如果选了gradle方式,杯具了,后面还是得所有用例全部执行。
如果用例编写未指定JUnitRunner,IntelliJ IDEA默认调用scalatest运行。此情况下,命令行gradle test则无法运行该用例
如果在gradle配置下加入运行,实际效果就是全用例运行。
好吧,为了自动化,只能采用在IDEA运行单个suite,在集成CI中运行所有用例。
BUT,不死心啊,因为gradle下无法指定class运行,意味着NestSuite必须本身和子集都运行一遍,等于重复运行了一遍。搜啊搜,试啊试,苍天不负有心人啊,最后,终于找到了 gradle下单独运行测试类的方法,(关键先生来了)
gradle -Dtest.single=NestSuiteTest(指定测试类) test -i
虽然是个就命令,但是管用,真的管用,看着下面的运行结果,这才长舒口气,忍不住要问候几句:
NestSuiteTest.NestSuiteTest NestSuiteTest.NestSuiteTest$$anon$1.UsergroupActorTest handleUserGroupPostRecord STANDARD_OUT
NestSuiteTest.NestSuiteTest NestSuiteTest.NestSuiteTest$$anon$2.UsersCfgActorTest handleuserpostrecord STANDARD_OUT
至此,我们测试用例重构大功告成。
3.单用例执行效率
这个和实际测试内容有关,八仙过海各显神通,改进不具备借鉴性,略过。
4.并行运行测试用例
并行运行可通过CI将用例在不同机器分布运行,或者采用用例并行运行的方式,略
Powered by feilin021014@sohu.com ©2017 Code licensed under an GPL-style License.Document licensed under CC BY 4.0 .The End
以上是关于干货|简单重构,显著效果-提升scala自动化测试效率之道的主要内容,如果未能解决你的问题,请参考以下文章
自动将通配符导入重构为 IntelliJ 中的显式导入(用于 Scala/Java)