阿里QA导读:新奥集团中台的陈磊为我们打开了AI测试驱动的视野,同时也深入浅出地介绍了如何打造智能化API测试框架。通过陈磊老师的分享,我们看到了AI-DT的无限可能性。以后,AI能不能代替大部分手动测试,还真说不定哦~
大家好,我是来自于新奥集团中台的陈磊,我有可能今天是所有嘉宾里面唯一一个不是在互联网领域,我今天给大家演讲的题目是:自动的自动化,一种自动化测试装置的实现。我从以下几个方面介绍一下,我在前面先讲讲智能化测试框架现在是什么样,我们现在整个测试行业里面,付费和开源发展到什么状况。然后我会重点介绍我们打造的一个自动的接口,自动化的测试平台,我这里面有可能不像前面两位老师讲的有深度学习,AI 没有这么烧脑,我用了一个很简单的我们最原始的方法解决了这个部分的事情。在后面我们会讲一下自解耦合和自测试的检测装饰,最后把平台大体的流程简单跟大家介绍一下。
智能化的测试框架
首先进入第一个部分,智能化的测试框架,现在这个方面这理念很热,这是我们分会场的主要的议题,我们来看一下智能化测试框架是什么样子,其实中文里面大家说智能化测试,有可能有两种含义,第一种是说 AI 或者是智能的框架可以完成的测试,还有一种是是智能化系统的框架,所以,我们在国外的语言里面他们把这个叫做 AI 驱动的测试。
现在 AI 已经走入我们的公众视野。AI 不断地渗透到方方面面,开发、测试、运维都有,例如 aixcode 智能的开发助手,完美完成人机结对编程,AIOps 在运维阶段也大量被提及和实践,那么测试呢?其实 AI 是很古老的概念,完成机器学习和深度学习,人工智能是替代人智能化的工作,它可以帮助我们做掉智能化的工作,如果说智能化的测试,是用人工智能驱动测试,是用这些智能化的算法或者是广义的自动化的一种算法或者是实现形式,来取代我们以前测试工程师做的智能化的测试工作。那测试工程师会不会失业,以后是不是不需要软件测试工程师。其实不是,我们测试工程师处于决策层,我们让人工智能更智能,所以这只是听上去耸人听闻,人工智能不是替代我们,而是让我们做的工作更方便,快速。
我们来看一下 AI-DT 的优势,这是我们的人工无法比拟,第一个部分更加精准,是因为它可以频繁地做一些事情,反复地回放一些测试 CASE。你会说,人工也可以回放 1 遍,2 遍,100 遍,但是人有认知疲劳,这些认知疲劳会影响我们的测试结果,但是机器不会,多少遍都可以,还有可以突破人类的极限,它可以完成大量用户的同一时间段的操作,这不是我们所说的性能,他可以同时做掉好多场景,业务流,但是它的更接近于我们某一个大型的并发系统,接受终端用户的访问行为,但是不能保证最后的流量和最后承载的压力验证的。还有执行的速度比人要快。一个复杂的业务流由人来执行,越复杂时间越长,我们之前做测试的时候,统计过我们人执行 CASE 一天 200 条,但是机器非常高。
但是好的执行,发起方不一定是测试,他有可能是开发,或者是产品驱动,他可以赋能研发,提高我们 CI/CD 流水化的程度,我们人把一个 CASE设计的再完美,它的覆盖度还是有它的局限性,但是机器通过一些算法,或者是自己的识别能力,做到一些分支语义覆盖的时候它的覆盖度更广,而且执行比我们人要快,要快很多,主要是机器不用休息,我们人是需要休息的,无论 996 我们也是需要有一部分的休息时间,但是可以让机器一直跑。整体来说用 AI 驱动的框架有很多好处,但是它不是为了替代我们而出现,而是为了帮助我们做事情更简单,更容易出现的。
我们将 AI 测试框架分为以下几个程度级别,第一个是原始级,辅助级,部分自动化级,有条件的自动化级,高度自动化级,全量自动化(科幻小说)级。科幻小说级就是跟我们看到的电影,跟我们看到的流浪地球无法想到的事情一样,现在是非常困难事情也是非常好的愿景。
下面我们详细说说这几个级别,第一个级别是原始级,我们自动化的测试行为,还是由我们人来写 CASE,由人来写自动化测试脚本,设计自动化测试,定位缺陷。当被测业务有了变更,我们还是需要执行所有的测试 CASE 去回放,去查探有没有失效的测试用例,检查未失效的 CASE 是不是全部通过。L1 级比这个轻松很多,L1 主要是说有一些算法可以帮助我们完成我们手动的复杂的而且又费时费力的工作,通过算法我们设计测试的输入 CASE,通过 CI/CD 的系统驱动执行,但是整个测试过程当中我们人跟现在一样,我们每次执行完以后由人打开报告,去看它的 BUG 怎么样,是不是有效的,去评价这个 BUG 级别。
L2 部分自动化级,主要是说通过一些算法识别一些比较容易出错的,比如说,脚本里面有一些容错的机制,我在回放脚本的时候,他有可能有的业务的一些流程没有更改,但是我操作的具体的界面或者是接口有了更改,他可以由自己的识别程度保证他执行完,但是人还是发挥了这样的决策性的作用,我还是要知道去判定它的结果是不是对的,我要区分每个 BUG 是不是有效的,如果有效的话,我要把他反馈给我的研发去修改,如果整个都测试完,还是由人决策,要不要把这部分的系统交给运维去上线,人还是发挥了主观能动性的作用。
L3 级别是有条件的自动化级,算法建立测试基线,基线是我们的黄金业务流,或者是所有的整个黄金数据流,通过脚本或者是算法生成测试数据和测试的脚本,自动去执行,但是这里面的人还是处在决策地位。
L4 是高度自动化级,它可以理解一些界面和人的行为,可以判断这样的一些业务逻辑是不是 OK,然后完成测试,现在大家都知道自动化是这样的,我们会要求测试脚本和测试数据,到这个级别的时候,你不一定需要有脚本,也不一定要数据,但是机器帮助你做一些事情,让你有了这些东西或者是他不需要这些辅助来完成,因为我们都知道自动化测试的时候,我们写脚本是为了完成我们人机交互,把人把这个业务业逻辑交给脚本,交配来执行业务逻辑。
最后一个级别是科幻小说级,什么都是有机器参与,我们人不参与。这个级别不是我们自己创建的,主要是来自于国外的一篇文章,而且整个的模拟的自动驾驶的分级方法。目前大家不用担心,我们绝大多数还是在 L1 级,有的框架在往 L2 级发展的趋势,发展到更高级需要很长的时间。
我给大家推荐比较商业化的 AI 的平台或者是框架。首款基于AI的智能测试工具叫 Mabl,它是由一群前 Google 雇员研发的 AI 测试平台,侧重对应用或网站进行功能测试。在 Mabl 平台上,我们通过与应用程序进行交互来 “训练”测试。录制完成后,经训练而生成测试将在预定时间进自动执行。它提供试用,我觉得思路跟我们之前有很多的区别,它是一个移动端的测试平台,你只要把你的被测应用告诉它,你不需要告诉业务逻辑不需要数据驱动,它按照自己的算法进行测试,定期发给你测试报告。这个工具披露的技术很少,所以我不知道它有没有测试脚本,也不知道它有没有测试参数,但是它可以给你所有的测试报告可以看到跟我们想要的东西几乎相差不远。
这些是商用的,我们来说一下现在比较流行的开源的 AI 相关的测试框架,第一个是 Test.ai,他是一个基于图形图像识别的开源的 APP 端的插件,他通过一些图像训练图像特征,完成测试业务,举一个例子,我要在淘宝上面买一个东西,我想要加车,点击购物车里面,他有很多去识别训练集,Icon 去识别训练购物车的按纽,就是购物车的功能,他就会自动去点击到这个功能,跳转到购物车里面,目前提供了很多的自己提供了一些样本集,大家可以下载下来,完成训练,但是有一个不好的地方,训练过程很耗时,但是有一种可能,我们的做 UI 测试的时候不一定需要 ID 这些属性,也可以完成我们的测试。
下面我在研究这个领域的时候,我发现一个 reTest 开源的插件他可以建立自己的黄金主流程的测试框架,我们适合它配合我们原来的脚本,我们有一个非常大的优势,我们原来写的脚本元素的 ID 发生变化,我再次回放的时候,脚本不会报这个错误,这个错误很常见,我们每次回放都没有问题,下次提交的时候这个错误跟大家见面的频率非常高。如果你用这个框架之后,它看不到这个,它会按照自己的逻辑让你完成你的措施逻辑,这是它建立黄金业务流的基线。
前面说了 AI,下面说说开源的 AI 单测框架,单元测试的发展比我们的 UI 和接口发展快很多,我相信很多人很早听说过最原始的方式就是静态分析,这是最早走入我们的视野,我给大家推荐两款开源工具,上面这个是基于文档,我想要跟大家多说两句,基于你的函数的注释生成单测脚本,他可以根据研发注释把单元测试脚本生成出来,我相信有的人跟我一样的困惑,我们研发不写注释,所以有没有都无所谓,所以我们学习了很多,研究了很多,后来发现有这样的框架可以根据代码写注释,我们没有往下探索,因为我们后来发现基于搜索的。
回头我们说一下随机的,推荐几个开源的框架给大家,但是我们试过以后效果并不好,所以我们选择基于搜索,其中一个是 EvoSuite,大家有这方面的需求可以下载试一下,它是基于一种搜索机制,它先是随机把参数进行一次随机,随机出来以后达到一个覆盖度,按照最大化覆盖逐渐生成入参和测试脚本,我被测的函数外部依赖很多,它怎么跑,它内部调用 mock 的框架,它建立这样的沙盒机制,自己生成入参的参数,它被被测的函数建立沙盒,前后在自己的控制范围之内生成最大的测试集,我们内部使用过程当中,发现行覆盖达到 88.85%以上,提供 4 种大家使用的方式,用命令行 jar 包调用,还有 maven,Plugin,我们发现有两个问题,它生成的 CASE 有很大的覆盖率,也许它正确的业务逻辑一条不包含,第二个是 CS 结构的框架,它有很大的好处,因为你运行的时候,如果是客户端去生成这样的单层脚本和入参,它的服务端可以保存生成完的数据,但是有一个问题,因为它通过它自解码生成单元测试脚本,有可能研发写得不好的函数,运行的时候没有问题加入自解码结果超过 64K 单方法的上限,这样会报错,要么研发拆分方法,要么只能等他们解决这个上限,现在是无解。
整个工具使用的时候,它提供一种好处,有可能一条正确的业务流没有在,它提供一条生成的 CASE 跟我们手写的 CASE 运行方式,我们只要把正确的措施落实手动的单元测试脚本写进去,它就可以完成很完美的覆盖度,完成我们原始的检测需求,所以我们把它放在我们流水线的检测下一级来调取。
智能化 API 测试框架打造
我们要做一个智能化的测试框架不是一蹴而就的,是因为有一些事情发生。我们团队大概平均的工作年限在 5 年左右,绝大多数人刚刚毕业的时候都是做业务测试,这里面从学校毕业大家都在手动写 CASE,在 UI 界面实行我的脚本,老师讲的东西不用,我们团队的代码能力比较薄弱,我们工作比较忙,我们平时被业务测试压得喘不过气,我们后面的自动化,我们跟所有的小伙伴聊天,大家学习自动化很难,学习代码,还要学习各种各样的框架,这些框架不容易学,还要花费很小,我们已经下定决心学习的时候,有各种各样的事情把这个事情淡化掉,每次下完决心翻两页书就终止了。
但是我们团队有一个很好的特点,我们团队对于大家通用的工具非常熟练,Postman 和 fidder 工具,他们看了半天以后,刚刚把决心学 TestNG,或者是 junit,他们搞得很迷茫,我们团队未来的被测系统里面没有 UI,我们必须要解决当前的问题,没有 UI,大家接近五年的工作经验对我们来说不好延续下去,我们要通过一种方式来完成我们的测试。
所以,我们团队内部考虑了一下之后,我们几个小伙伴设计了一个我们觉得挺简单的一个测试框架,我们的框架叫做 AAT,如果作为普通的 RPC 接口,你要理解一下 spring,你要理解 Maven,还有 Java,还有一个我们打造成类似工具的使用手册,因为我们团队小伙伴对工具很熟悉,我们设计得参数使用方法差不多,大家可以对应 Maven 的思路,我们觉得很简单,但是我们发现测试代码仓库没有增长,我们和小伙伴聊天,他们说面对人代码开发的黑色框框的时候不知道怎么开始,觉得很困难。
在我的老板这里我显得很尴尬,我已经说没有问题,后来我在想,我们要办法解决这个窘迫的界面,所以我们开发框架的小伙伴聚集在一起开始讨论的问题,这个时候有小伙伴提出问题,既然大家排斥写测试脚本,我们能够用框架把脚本写完吗?根据这个思路我们建立自己的数据结构,这个数据结构是这样的,大概有 5 个部分,name,type, leftchild,rightchild,facheer,这样说并不是很直观,我举了一个例子,这是一个接口,里面传了三个参数,第一个参数是基本类型,第二个参数是年龄,第三个是户籍。这个户籍里面嵌套在里面,第一个是基本类型,他说的是户口地址,第二个说的是户口属性,我们根据这个代码,以及刚才所说的数据结构和算法,我形成左边这样的一颗树。我们来看一下我们的入参第一个参数是名字,是基本类型,所以我们建立一个存储的数据结构,第一个是变量名,第二个是 type,入参的类型,左孩子指向第二个基本类型,我们来看一下第二个入参基本类型,后面是一样的,我们往后看他是一个复杂类型,这个复杂类型我们建立一个同样的数据结构,我们第一个存的是复杂类型的变量名,第二个是存 type,我们看到户籍里面是两个基本类型,所以说,第一个指针建立一个基本类型的存储节点,再往后还是一个基本类型,所以说他有一个左孩子,但是我们后面没有右孩子,我们建立这样的一个数据结构,在内容里面,我们对他进行深度优先的便利,我是我们生成测试脚本。
看着好像还好,这里面有一个小问题,第一层的入参拿不到变量名,对于我们做接口测试来说原来叫什么不重要。我们只要知道它是什么,我们传进去,我们人对照实际的语义含义,我们做完以后,在内部做了简单的培训,怎么使用,我们让所有的小伙伴测试,我们感觉还好,我们的代码仓库增长得很快,但是后来我们发现,我们知道所有的自动化都是这样的,测试脚本是帮助我们实现逻辑的,另外还有一部分是我们的入参,我们的参数辅助先给一些,我们后面做自动化,我们开始推荐的入参,我们一个小伙伴在会议上面有一个老师讲过,TDS 的数据测试服务,结合我们自己内部的特征,我们建立自己的数据服务。
这里面数据服务有三类,第一类是模糊的,我们经常听到的一些远程注入攻击类,我们采用是一个开源的工具,加入到我们的服务里面,第二个部分根据我们自己内部的一些数据的实体属性建立我们的数据实体,我们也是看到的是 Facebook 开源框架,他推荐用数据的 Mock 形式,我们建立自己的内部实体,比如说,人,人下面有属性,我是陈磊,我的住址等一堆属性,我们逐渐地模拟出来,生成我们为了以后的测试调取数据获取一些参数,最后一种跟前面几位老师讲的有点类似,我们把线上的数据导入到测试环境,但是我们没有流量,我们只要了测试数据,我们在原来的接口的所有的接口的入口的地方加入一个拦截器,我们导入到大数据平台,大数据平台有地方存,第二个可以帮助我们脱敏,我们把所有的线上数据导入到大数据平台,我们有一个固定时间的开关,人为驱动开不开,我们从大数据里面加入到这个系统里面,我们开 10 分钟的时间,数据量很大,我们最开始选用一种有监督的聚类算法,我想要找到几个好的,但是我们尝试以后发现,我们把算法更换,把比较有代表性的数据拿出来存储在数据服务里面。
我第一次测试服务的时候,在我的接口接入测试平台以后,分析它有几个参数,我需要我的测试工程师人为标记对应哪个属性,这里面拿到的数据跟我所有的数据都通过数据实体的形成对外暴露,完成接口跟现有参数的对应关系,我会通过一系列的方法把这个参数存在我生成的测试脚本里面,这个时候我们觉得有了一些推荐,大家省了一些力气,好像我们做了一些事情,这些事情大家的接受度比较高,所以我们把整体的思路和我们前面的原始算法跟这边的数据实力整合成一般整个测试平台,大上面整个流程就是这样。
说话是配置接口的依赖,我要知道他依赖什么,我要依赖什么,我要调什么参数,我会一遍一遍生成测试,拿去我的接口测试代码的覆盖,但是我们关注的是测试接口入选决定的条件服务都被我这次测试走到了,如果没有,我会调取重跑机制,让 DTS 走到没有走到的分支的参数,我要走过去,整个过程循环执行下去,他有两个结束测试的标准,第一个是每两次运行生成的参数以后,我的测试的条件的覆盖没有增加,我就停止,第二种是我的入参决定了分支都覆盖了,我也停止,跑完以后,我们把测试报告和我们刚才所说的覆盖报告统一到一起发到我们的数据聚合报告的服务里面。
我们觉得很得意,大家很快完成这个事情,老板要求的任务我们满足的,但是微服务越来越多,我们发现我们整个测试慢慢地越来越痛苦,我们上面的事情做的这些事情没有想到效果,为什么呢,我测试 A 系统,A 系统调取 B 系统的服务,B 系统不稳定,我们测试 A 系统的数据和 A 系统的脚本,无法完成任务。我们调取发现是通过接口调用,我们可以生成测试脚本,我们可以生成 Mock 服务,我们把外部的被测系统所有的接口都进行了解耦,解耦部署,你要调用 A 服务,不知道他稳定不稳定,他会生成一个解耦的别名,这是唯一的,我们会获取原来的项目的 pom 文件,它的数据来自于我们的 TDS,最后我们统一容器运行起来我们这次解耦的这些服务在注册中心注册,我们的被测服务起来以后,发生交互是我们自己的解耦服务,所以,他完全是在我们的这个沙盒里面做测试,既然外面不稳定,我们想办法外面也是自己来生成。
我们说 Alias 生成解耦的算法和解耦的 VID,他按照项目统一生成,还有维护这些东西的存活,通过心跳去判定他是不是活的,如果他有问题,他再次按照原方法从头到尾执行一遍,我发现提起的 Mock 的服务还是死的,这个时候我们发通知给测试工程师,平台机器无法解决的问题需要人去修复,整个过程测试完以后,他会负责注销掉所有的包括 Mock 的服务,包括容器,包括所有的唯一的 ID 都会被销毁掉。
这就是我们测试完,我们需要进入集成部署,把所有的我们 Mock 修改掉的东西回归原位,再进行测试,相当于我们把 API 测试做成接口测试层面的单元测试。整体我们来看一下大体的平台是这样的流程。
我们开始在 CI 里面做测试的时候,后面生成调用脚本的算法,会生成我给大家看到的这一页,同时生成入参嵌套的 json,整个过程当中解耦服务通过 Alias 管理完成你的 Mock 的生成部署以及销毁,整个的测试过程当中我们把所有的测试,这是我们的脚本测试的结果或者是运行过程当中的观测界面,我们会把单元测试,还有我们接口测试的报告,还有结合测试的覆盖报告打到我们的聚合报告里面,大家可以按照项目拿到你横向纬度的结果,统一进行查看。
以上就是我所有的内容,谢谢大家。