【NCTS峰会回顾】搜狗科技王鹏:如何通过精准测试来解决效率黑洞
2019年10月26日,由Testin主办的第二届NCTS中国云测试行业峰会在京召开,此次峰会以“AI+未来”为主题,汇聚来自国内外测试领域的知名专家学者、领先企业决策者、高层技术管理者、媒体从业者等,共同探讨高端云测试技术,帮助测试从业者了解最前沿行业趋势,及最新的行业实践。
搜狗科技资深高级测试开发工程师王鹏做《如何通过精准测试来解决效率黑洞》主题演讲。王鹏指出,“精准和智能是精准化测试聚焦的两个点,而如何从经验型方法中提升技术性的手段则是精准化测试的目的。”
以下为王鹏演讲实录:
大家好,今天我给大家分享的主题是《如何通过精准测试来解决效率黑洞》,我希望大家听完后,可以想想现在适不适合开展精准测试,如果现阶段不适合,我的目的也达到了。第二点,如果确实可以做精准化测试,我希望大家听了以后学到一些方法,能知道哪些阶段引入哪些方法可以解决哪些问题,达到什么效果,想做的话,回去后,可以开始一步步开展。
分享分三个部分:1、影响我们测试效率的因素有哪些,既然做这件事肯定是事出有因的。2、简单介绍一下精准化测试思想。最近精准化测试起来了,有的同学对此了解不是很深。3、介绍一下我们提升效率的具体方法有哪些,每个阶段都会详细给大家介绍。
首先说一下影响效率的因素,这是和大家诉苦了。我这个题目选了“黑洞”这个词,大家看这张照片是前一阵NASA发现的第一张黑洞照片,选这个题目的时候,这张照片还没有呢,为什么选黑洞,效率为什么是黑洞,因为他们有类似的地方,黑洞是什么?质量特别大但是体积很小,我们平时工作是什么样的?测试的工作非常苦,付出非常多,但有可能成效非常少。是什么造成了这样一个情况?
分析了一下:
1、投入产出比。不知道大家平时做事的时候有没有考虑过这个事情,这个事情其实对你自己的影响非常大,大家可以好好想一想,经常有人说我们工作效率低,这直接对我们个人的影响就是你的创新性工作启动特别难。作为一个测试工程师,如果我正天被我的工作羁绊,成天做重复的工作,也许很多人都是这样,最开始我也是这样,那么就很难开展一些创新性的工作,或者你和老板提出有一些想法要做这些创新工作,也可能没有时间,老板会跟你讨论,这些创新工作投入产出比怎么样、收效怎么样、付出这么多时间下面如何?这是我们面临的困境。
2、我们的成效不可衡量。这个很多分享嘉宾提到了,不出事还好,一旦线上发现什么问题,往往追溯的时候,开发可以查代码,我们整个测试过程怎么回放,不可衡量,我昨天这么点的没有出现问题,今天还是这么做出现问题了,你说我到底错在哪儿?我们的工作不可衡量的话,真正较真计较这个事情的时候,我们就处于非常非常被动的地步。
正因为这两部分,这次出事了,下次投入更大的精力去做,从另一个角度讲就是影响你的效率。
说完我自己的切身体会再来回顾一下我们平时的工作,我列了两项:黑盒测试,白盒测试。大家可能觉得老生常谈,其实不是这样的,黑盒测试我们今天听分享有好多高大上的方法,据我们了解,在很多大厂包括很多公司里,黑盒测试的同学仍然占80%以上,这是不可规避的一个问题,大量的同事还在从事着黑盒测试工作,那么我们怎么帮助他们其实是一个非常重要的问题。
说到黑盒测试,准备从三个方面说一下,过程、效果、管理。黑盒测试的过程是怎样的?因为黑盒测试是看不到代码的,在整个测试过程中伴随着很多猜测的成分,在测这个功能的时候可能凭借你的经验猜,它可不可能出现一些问题,设计测试用例的时候也是靠猜的。第二不稳定,体现在很多方面,极端的例子,今天测的和昨天测的可能就不一样,今天身体不舒服测的版本效果可能跟身体好的时候也不一样。第三难控制。正因为这么多因素造成整个黑盒测试的过程是不可控的,我说测一个90分的版本来,怎么确定这件事情?
效果跟个人素质关系很大,一个新人和一个有经验的老人对业务测试的质量,这个区别是很大的,在座很多管理者,如果你管理的是一个黑盒测试团队的话,你面临的难度是什么?要管理测试开发团队评估你的代码开发能力、代码设计能力,其实不是一个很难的事情,咱们打几次交道,你给我实现几个功能就基本知道你的底了,就知道什么样的工作可以交给你开发,业务怎么办?你可能有自己熟悉的业务,比如说来了一个测试需求,测试需求里的很多业务,30%是你熟悉的,70%是不熟悉的,能不能交给你,如何选择一个合适的同事测这个版本?这是一个非常大的问题,是对黑盒测试团队管理者提出的很大的挑战,出现问题时我们反思,测试过程中这个问题需要注意、那个问题需要注意,管理者有没有扪心自问为什么选择他做这件事情,如果选择另一位同学能不能规避他犯的错误?这是很难的事情。
另外聊一聊白盒测试,在座有做白盒测试的吗?有两个,不知道你们是不是互联网行业的,其实我是不建议在互联网行业做白盒测试的,因为白盒测试产生是以前像微软Office这种开发周期极长用白盒测试,互联网一天上线三个版本,做完以后门槛高,团队里有一到两个人能做白盒测试吗?单兵作战,你测一半能不能交给另外一个同学?没法交接只能自己做。第三目标比较单一,做白盒测试的时候一般评价我们测试是否到位,基本只能依靠覆盖率,白盒测试过程中覆盖率达到一定指标了就说明OK,目标非常单一。还有没法大家一起做,一个版本来了大家一起做白盒测试,最后把结果汇总到一起,这个也是很难做的;第四就是分析之殇投入产出比比较低,有可能做完以后只能告诉“看了,这些逻辑确实都覆盖到了,没有问题”但是你发现bug了吗?一个也没有发现,这种情况很常见,所以白盒测试对于互联网行业是不合适的,所以现在其实很早大家就在做灰盒测试了。我们基本上测试是通过黑盒测试做的,在黑盒测试基础上更高效的解决问题。这是我们面临的现状。
第二,就给大家介绍一下精准化测试思想,简单介绍一下,这有一句话我念一遍,因为我看过很多精准化相关的资料,我认为这句话总结的非常到位,精准化测试就是“用非常精准和智能的软件来解决软件测试的问题,并从根本上引领软件测试,从经验型方法向技术性方法的转型”。它强调两点,首先当然是需要解决问题的,精准和智能是精准化测试里要聚焦的两个点,如果做精准化测试一定要聚焦在这两个点上,它要达到的目标是什么?从经验型方法向技术性方法转移,黑盒测试大多依赖于经验型方法,如何在经验型方法中提升技术性的手段就是我们精准化测试的目的。
分别介绍一下,首先介绍一下精准要做哪些事,我们这边的精准1、测试用例到代码逻辑精准记录的双向追溯。什么叫双向追溯,执行黑盒测试用例直接就能映射到你的代码逻辑上,看代码逻辑也能反向用到测试用例上,一定是双向的,如果是单向的,这个效率是提高不了多少的。怎么实现?代码逻辑到测试用例是通过函数调用关系计算来的,我们提出一种方法叫代码染色,这两个都会在后面详细给大家介绍。
2、精准的代码级的缺陷定位和崩溃分析。在做黑盒测试的过程中,我们一定要给黑盒测试同学提供什么样的方法?测着测着发现一个bug,他自己就知道哪块代码出问题了,要达到这种效果,崩溃也是要能落到崩溃分析上。
3、精准的测试充分度分析,主要是解决测试不可度量的问题。
智能有哪些?主要列了3点:1、回归用例的自动筛选;2、自动化用例筛选与执行;3、持续集成。
第二部分就简单介绍到这,主要介绍第三部分,告诉大家如何去做,上面那些事,如果我想做的话一步步怎么做?我给大家分享我们在搜狗社区具体应用的案例,我们现在正在做的事,大概是做成什么样子。
首先再给大家提一下影响效率的因素,因为我们这里主要要解决效率的问题,列了很多,刚才也有人说过了,1、团队新人没有经验;2、团队新人能力不足;3、测试范围圈定凭经验。这里我们经常遇到那种情况,开发改了一段代码,需求上写的很清晰,我们都测到了,但是却有另外一个场景出现问题,是有关联的,我们很难把那部分测试用例圈出来。4、测试用例筛选难,让你从曾经的测试用例筛选出这次的测试用例,这个很难。5、测试经验沉淀效果差,我们这个测试经验沉淀基本是口口相传,沉淀的东西是静态的,无法动起来,看代码、整理接口、就编成一篇篇测试文档,或者在某个软件、某个平台里落在那儿了,它动不起来,不实际,用到不会查,查还可能查不全,怎么让这些资料主动为你提供帮助,这是我们做的事情。6、测试人员状态不稳定,主要是指大家的心理和生理状态。
最初我们给自己提了4个目标,我们要解决的问题:1、要精准圈定我的测试范围;2、对影响的范围必须给出建议;如果测这个版本要有个东西,暂且叫它软件,要告诉我还有哪些东西要考虑。3、自动筛选测试用例,要测这个版本了,至少给我一份测试用例让我做参考。4、为黑盒测试提供实时覆盖率结果。
为什么强调实时覆盖率改革呢?有时候我们经常做覆盖率,一堆功能做完了,让我们出一份覆盖率软件去分析,发现有几行没有覆盖到,再往回推,效率也是比较低的,我们要达到什么情况?比如,我执行了非常短的业务流程可能就是一个登陆,三步操作,输入用户名、输入密码、提交,这三步操作希望知道我的覆盖率是什么,及时调整覆盖用例,这个对我们价值是比较大的,所以我们必须为黑盒测试的同学提供实时的覆盖率分析。
刚才说了那么多我们一步步介绍,下面是具体每一步是怎么做的:
筛选测试用例,一共做了三步:版本提测的时候做哪些事情,首先会提供提测版本的信息和线上版本的信息,我们对这两个版本进行diff,计算出diff结果,结合变更函数计算,通过调用函数关系的计算,现在想想diff软件里面是有很多代码段的,告诉你在哪一行发生了变化,这一部分是他提供给我们的信息,我们要从这个信息里得到什么结论呢?首先要把变更函数计算出来,这些代码段映射到函数上是哪些函数发生变动这我要知道,那么和这些函数相关联的还有哪些函数?它的调用关系我们要知道,要做到这两点,要从diff结构解析后面两部分。第三是测试用例生成,解析出来的函数映射到测试用例上,这些函数发生变化或者这些函数关联的功能发生变化就可以把这部分测试用例筛选出来。
针对依赖关系举个例子,开发为了实现功能1,同时修改了函数A和函数C,其中函数之间调用关系功能1是C调用A,功能2是B调用A,开发是改了A了,提了C这个场景,B调用A就可能出现问题,函数调用关系计算就是为了解决这样的场景。
我们这边服务端的语言都是JAVA,所以我们是使用了JAVACG工具,通过对class文件解析计算函数之间的调用关系。具体就是如图这样的结果,当你解析对于class稳健的时候会输出这样的文件,一大堆调用关系在上面,但是只是一层调用关系,我们需要通过这种一层调用关系把他们串起来,左右关联一下就可以了,所以我们要把函数调用链关联起来,当然你也可以看到,其中有很多第三方库的函数调用关系,其实可以通过过滤器把不相关的过滤掉。
diff结果解析怎么做的,变更代码段,解析diff结果文件,计算变更文件名和变更代码段的位置信息。它会写第三行第五行发生了一堆操作,这个代码段我们要通过整个diff结果文件算出JAVA文件里的代码信息解析出来要保存。变更函数怎么办,我们通过扫描源文件和代码段的信息判断一个包含关系,比如函数A包含了这个代码段我们认为函数A发生了一种变化,通过这种方式计算变更的函数分类。影响范围怎么计算?结合函数刚才说的调用关系,圈定受影响的函数范围,是这样的流程。
举个例子,比如diff结果,A.java,code有个开始位置、结束位置,A.java原文件里也有这些信息,你会问,如何判断一个函数结束的位置,开始位置可以判断,因为你知道可编译的函数自己本身是有编译器的,不用达到那个级别,比它简化很多,只要把函数位置提取出来,肯定是有一个class特征的,函数开始位置是没有问题的,结束位置大概理解成下一个函数开始位置的上一行,但是可能有细节,有嵌套类、其他函数的套用,这一块细节的地方处理一下但是整体思路是这样的。所以如果第一个代码段落到函数1的区间范围内的话,我们认为这个代码段属于那个区间,大概就是这样的过程。
如图就是具体解析SVN diff的结果,代码段,大家拿到PPT可以详细参考一下,我不详细讲了,非常简单。三种定义方式我们如何判断函数,只要把函数信息确定,位置信息拿到就可以了,不用做更深的分析了。
我们实际达到的效果是什么?我们要达到什么样的效果?以我们工程为例,给出两个版本号,这两个版本是这次提测的版本和要比对的版本,底下就会把它的变动函数计算出来,这个变动函数就包括依赖的函数,因为这两个选的比较近,改了这些内容,我们这次需要关注的所有范围的函数信息就在这里。
前面主要介绍从代码层面影响范围,最终还是要落在测试用例上的,这是最关键的事情,那么怎么做的?其实我们也是从一些笨方法开始的,这个东西有时候不可能一下达到最优的方式,给大家介绍一下整个的历程,大家可以思考一下。
首先,人工录入是一种非常低效的方式,但是为什么从它开始呢?因为我们以前就做这件事,我们其实虽然不做白盒测试,但是我们也是做灰盒,测试人员也是需要看代码的,看代码了就让他录入时比较顺手,这件事情不可持续只是它原本效率就很低,人工阅读源码梳理与业务相关的函数,并与测试用例建立相关性,看懂了这个函数,觉得和哪个用例相关的就人工手动关联上。这种占20%,他们会提一些抱怨,我们怎么给他们提供辅助信息,工具也跟开发达成一致,因为他们也希望提高自己的代码质量,要求他们写良好的注释,我们推动开发撰写注释,使用工具把函数和注释信息抽出来,那里面有和测试用例对应的场景,还是需要人工建立测试用例的相关性。这一块大概占30%,我定义叫中效,其实它的效率也不高,而且还有可能开发写的注释,你理解上有偏差的地方,但是比第一种又多了一些辅助信息在,其实最好的是比较高效是代码染色的工作,根据测试人员行为自动录入测试用例和函数的对应关系,我们特别希望做黑盒测试的时候可以录制黑盒测试行为,这样是最好的方法。
可以看一下最笨的方法是用excel的方式,并不是强制要求大家从零开始做这件事的,其实之前也开始做这件事了,只不过要求它和测试用例级对应上,后来我们提供了一个平台,但是没有从根本上解决这个问题。如图这是做代码覆盖率的时候,做覆盖率分析的时候可以直接把函数相关的内容录入进来,效率是有提升,但是还是没有解决最根本的问题。
给大家介绍一下代码染色的思想,代码染色分5步,离不开覆盖率,首先我们在执行黑盒测试用例的时候,会收集覆盖率,因为我们已经做到了黑盒测试覆盖率的实时收集,比如开始录制我的行为的话,黑盒测试执行一段行为,收集覆盖率,解析覆盖率的结果,覆盖率当中发生变化的函数和这一次执行肯定是有关系的,我们会把这些代码进行染色,染色就会和测试用例级反向对应上,再结合之前的函数调用关系的计算,相当于把范围稍微放大一点,这些函数如果发生变化的话都会映射到黑盒测试用例上,这样就形成了双向追溯,执行用例也可以到函数级别,函数级别变化可以映射到用例上,这种方法效率就得到了很大的提升。
筛选测试用例的流程如图,首先是基线版本代码和测试版本代码diff,对diff结果进行解析计算变更的软件和方法,计算方法会把依赖关系入库做比对,如果发现库中有的话,直接会从用例库里筛选出来,有一部分新增的需求肯定是要手动撰写用例的,这部分没有办法,需要手动把用例补上,最后合并成一份完整的测试用例。
如图这就是我们最终达到的结果,当你筛选出来结果的话,包含所有函数的信息以及对这种函数的理解和最后要执行的测试用例级,点进去可以直接执行测试用例。
简单给大家说一下覆盖率,我们主要做两种,JAVA覆盖率和JS覆盖率,JAVA不多说,大家都用jacoco,但是我建议用on-the-fly模式。JS我们选择了一种工具,大部分工具都是支持单元测试的,对我们黑盒测试不是很友好,我们基于JScover做了二次开发,实现插桩上报加代理的方式,同时支持源文件和ES6编译文件的插桩。
JS多说一句,覆盖率无非要做四件事,代码插桩、数据上报、文件映射、生成报告。代码插桩主要针对源文件和编译文件,JScover就可以做这件事情。数据上报可能需要改动一些代码,文件映射需要一个代理,把所有线上的请求映射到本地这一块需要有个代理。生成报告这块,实际上自己支持的也比较好。
数据上报,可以通过一些事件进行数据上报,这里列了两个,比如页面切换,像测PC的时候,如果页面发生切换就让它报上来一次就可以,无线的话可能涉及到滚动,这样的话一般是鼠标移动,不要行行都报一次,那样对业务测试压力比较大,比如鼠标往下滚动一次,鼠标有操作了就报上来一次,这种不会发现前端测试有性能问题,工具引起的性能问题不会有,这个效果还不错,这个大家感兴趣可以回去看一下。
说一下ES6,为什么要兼容ES6标准呢?前段时间大家都用JS框架开发,他们都是采用ES6方式了,已经不是原生JS了,之前是在JS插桩就可以上报了,需要编译的话像右图这种怎么办?选择一个什么节点进行插桩呢?源码是易读不可执行的,这种插桩没有意义,编译后较易度可执行,压缩混淆后不易读,可执行,我们选择了这种方式对编译后的插桩,这样可以选择ES6的开发模式。
大家参考一下就可以了,这是我们一个覆盖率分析的,有JS的工程也有JAVA的工程,都是支持立即收集覆盖率的,前端做一些工作就可以覆盖率实时察看,这是覆盖率的基本信息,如图相当于左边是JAVA的结果页面,右面是JS的,JAVA这一块有一个bug的提示,相当于这是一个diff结果,看哪块没有覆盖,如果对这一块函数有告警说它有bug的话也可以察看,都可以打通。这是我们整个的测试流程,把它列在这儿,如果做精准化测试的话,可以在哪个部分把这个事情做了。首先提测前,跟大家差不多,需求评审、用例编写、用例评审、提测前准备、提测走查,这个主要支持在提测到预发布、上线支持的部分,我们筛选出来的测试用例不仅用于测试人员而且还用于开发的提测前的默验测试以及产品提测前的走查。