智能化测试探索
大家好,我是来自京东的陈磊,我今天演讲的题目是《智能化测试探索》,今天的演讲主要从两个方面阐述,先说一下自动化测试现在的现状,然后会详细讲一下我们在智能化测试上的探索。
首先,要讲一下自动化测试的现状,我相信绝大部分公司都是这样。
手工测试工程师做case然后测试开发工程师依据测试case编写脚本,撰写测试数据,调试测试脚本,然后是提交测试脚本,自动化测试就被迫到了回归测试阶段,自动化测试永远也赶不上RD的开发进度。我们团队也有这样的状况存在,这里介绍一下我们部门的一些背景,我们部门的被测系统是中台系统,重点是接口测试,我们的被测接口绝大部分都是京东内部的RPC服务协议JSF。在我们的团队里,测试工程师每天要花费大量的时间编写测试脚本脚本,因此我们在想,如果可以想办法提高测试脚本的编写速度,就可以提高整个团队的工程生产力,提高ROI,因此我们就着手通过一些方法解决测试脚本的问题。我们设计了测试脚本自动生成算法,来用程序完成测试脚本撰写的问题。
我们设计了一种数据结构,就是这样页所示,我们采用一个类二叉树的结构存储函数以及其入参的嵌套关系,一个树节点中包含了名字、类型、左孩子指针,右孩子指针和父亲指针。下面用一个例子来详细介绍一下这个二叉树是如何产生的。其中被测接口是SetPersion,其中入参有一个复杂参数household,户口类HouseHold入如这一页所示。那么通过我们的自动生成算法就会形成如下的一棵树,其中根节点存储的是被测接口的信息,根节点的做左孩子指向第一个基本类型变量节点sName,被测接口的第二个入参还是一个基本类型节点,因此sName节点的左孩子指向iAge节点。下面我们看到被测接口的入参是一个复杂参数,因此根节点的右孩子指向一个household节点,然后可以看到HouseHold类包含了两个基本类型,因此household节点左孩子指向HouseHold类的第一个基本类型节点是sAddress,sAddress节点左孩子指向HouseHold类的第二个基本类型节点sType。然后我们通过深度优先遍历,按照我们自己的接口测试编码规范生成了基于TestNG的测试脚本。同时,也生成了一个参数嵌套关系的Json文件。
解决的脚本问题,我们就信心满满的开始大力推行接口测试,我们发现测试效率没有太明显的提升,我们发现被测接口有时候变动很大,每次在开始一个测试后,等待全部选中脚本都执行完后,查看报告才发现很多被测接口发生了变成,这无疑浪费了很多时间。因此我们有一次陷入了问题当中。这次我们要解决被测接口变更测试脚本没有及时迭代的问题,我们设计并开发了运行变动检测算法,这里我们借鉴了Git的思想。首先我们会给我们第一次生成的脚本和参数嵌套关系Json文件执行一次MD5,在服务端执行测试的时候,首先依据被测接口再次执行一次上述的测试脚本自动生成算法,然后也会计算MD5。然后我们会分别比对各自的MD5值是否一致,如果都一直那么执行测试;如果参数嵌套关系的Json文件的MD5不一致,通过邮件通知脚本的Owner,需要人工介入,如果测试脚本不一致,那么新生成脚本替换老脚本后,执行测试。
就如同茹老师讲述的内容一项,自动化除了脚本还有数据,我们有一个TDS测试数据服务中心,他提供三种类型的数据来源,一种是模糊数据,我们直接引入了fuzzdb的开源项目,第二个是数据实体,我们才考了facebook开源的mimesis,在内部对我们内部的所有数据实体进行了抽象,例如我们有一个Person的数据实体,它有姓、名、配送地址、银行账号、username等等一系列属性,通过一个generator生成数据提供给TDS使用。还有一种数据来源是智能化的数据,主要是通过在线上环境的服务端加入拦截器,通过拦截器将一些拦截脱敏后存入大数据平台,然后通过一些聚类算法对数据进行训练,对一些抽取聚类中心的数据提供给TDS使用。做到这里我们就像既然数据有了,脚本有了那么是不是可以让脚本自己去TDS里面获取数据。因此我们设计了一种交互语言Hil,Hil是一种测试脚本和TDS的契约,是服务和服务间契约的达成载体和实现方式。Hil有两种语法,一种是无约束的举个例子,我想选一个人,这是他的姓名,地址,通过如下语句解析出来下面的数据,返回结果是随意给一条;另外一种是有约束的,我通过这条语句拿十条数据,TDS会按照要求返给我10条满足约束的数据。脚本就可以通过Hil和TDS达成数据契约,告诉TDS我需要什么样的数据,这就成了脚本和TDS的交互通道。
我们还设计了自动重跑机制,每次测试完成后,会读取代码覆盖报告,要获取代码的覆盖率报告,我们使用的是Jacoco,然后提取覆盖率小于预期的被测接口,分析未覆盖条件所需的参数,生成Hil语言,发送给TDS。TDS生成数据存储到对应测试脚本的参数池中,再次执行测试,就这样循环直到覆盖率达到预期或者没有新的Hil语句生成。
整个执行流程大体是这样的,我们有一个CI系统是全部上述流程的总入口,这个CI系统满足调用的API,按构建调取,按周期调取,按需调取等持续集成需求。CI系统会按需求调取脚本自动生成,然后通过Hil让TDS会产生一条数据,这条数据我们也不知道是什么,但是它会按照预设好的语义产生一条数据去测试,然后先检测一下这个被测的脚本和接口有没有变,如果没有变化就执行,如果变化了就再次生成一个脚本。然后就开始进入上面的自动重跑机制,测试完成后会产生一份接口测试报告和最终的代码覆盖报告,通过聚合的方式推送到聚合报告系统的,目前整个项目还在内部调试的过程中,目前来说还有一些收益,能省掉一些人工,但是目前还并不完全。我的演讲就到这里,谢谢大家。
提问:我想请教一个问题,刚才讲通过智能化的测试,我没听懂你的调研怎么做的,怎么通过测试保证程序的正确性,这块是怎么保证的?
陈磊:其实结果的检测保证它没有问题是因为我们已经采取了单元测试的思想,保证一些代码的覆盖,覆盖到以后,它就不会出现错误的信息流向,因此可以保证被测系统的质量。
提问:按我的理解,即便是达到覆盖,走了分支,但是并不代表这个程序就是正确的对吧?
陈磊:目前被测还是Single API的脚本,对流程化的和强上下文的目前还没有进一步研究。