作者:闲鱼技术——问衿
一、背景
在服务端的质量保障中接口测试一直占据着重要的作用,从最开始的手工测试到编写接口测试代码,再到后来的基于流量录制的接口回放,测试效率不断得到提高,但是风险评估主要还是依赖开发同学以及测试同学对业务的熟悉程度,没有相应的工具予以支撑,回归的时候也没有重点,通常会全量回归,避免遗漏。因此开发相应的工具及平台精准确定代码的改动范围,有效评估影响面,提高回归效率。
二、方案概述
服务端主要对外提供 HTTP及RPC 接口,可以将其看作是入口型的接口,流量录制平台通常获取的都是HTTP 及 RPC 级别的流量,因此我们主要的解决思路如下:
step1:通过订阅 Gitlab 的消息获取代码的改动信息,包括改动的代码行范围,修改的类文件等
step2:分析代码的差异,根据改动的代码行范围判断修改了哪些方法
step3:通过流量录制平台本身的能力获取 HTTP及 RPC 接口的调用链路,建立方法和入口接口的映射关系,此时根据修改变动的方法就可以查询到对应的入口接口
step4:通过流量录制平台获取到对应的流量用例。其中录制的就是HTTP及 RPC 接口流量用例
step5:建立变动方法与流量用例之间的映射关系
下面就通过主要的四个方面展开阐述:代码差异化分析,方法调用链路解析,流量录制,用例关联。
图1 流程概览
三、代码差异化分析
代码改动之后,我们希望知道代码改动的影响范围和影响程度。影响范围包括影响到了哪些接口,影响到了哪些调用这个接口的应用;影响程度指的是影响的接口或者应用是否是强依赖或者是核心的,目前我们实现了获取到影响到哪些接口的能力,其余的内容我们计划后续实现。图2是代码差异化分析整体流程图。
图2 差异化分析流程图
对于代码的差异化分析目前我们支持 Java,Objc,以及 Flutter。Java解析使用开源的Java解析器,Objc 及Flutter通过各自的语法进行处理,自行实现了简单的方法解析器;其中在解析时使用了Gitlab传递过来的变动代码行范围数据,通过代码行来进行检索判断。考虑到 Java 解析器有现成的开源工具,Objc 以及 Flutter 需要自行实现,现以 Objc 举例说明具体的解析过程:
1、根据 Git diff 信息获取变动的代码文件路径及代码行范围,如图3 所示,变动的代码行范围是[1200,1207]。
图3 Git diff 信息
2、在步骤1中我们可以获取到变动的代码文件路径,可以下载对应的代码文件作为解析的数据源
3、按行解析,判断该行是否是方法声明,如果是,记录下代码行数作为当前方法的起始行,同时按行向上搜索判断是否含有方法结束标志,如果有那么记录下行数作为上一个方法的终止行。最终我们获取到了代码文件的类似 AST的一个数据结构,其中以方法块的形式记录了各个方法名及其起始和终止行数。比如图4展示了对应的数据结构。
图4 方法块数据结构
4、根据 Git diff 中获取的代码行变动范围在上述的方法块数据结构中检索,如果代码行范围是方法块行范围的子集,那么就命中了该方法,就返回该方法名,根据图3的代码变化范围可以在如图4 的数据结构中发现匹配的方法名是 getName。
三、方法调用链路解析
方法调用链路的获取我们采用流量录制平台提供的能力,但是由于获取方法调用链路的模块在加载后对应用的响应时间影响比较大,目前该模块只在预发加载,因此我们需要录制预发的流量,预发的流量仅用于方法调用链路的分析。
图5 流量录制与方法链路获取
图5 展示了预发流量的录制与方法链路的获取流程。获取到预发流量之后,我们通过流量的唯一标识id调用流量录制平台的API获取整个调用链下的方法,举个例子,比如RPC接口:com.idle.test.openService@getInfo~II,如图6所示可以获取对应的调用链信息,根据其中 method 字段即可解析出方法链路列表,因此建立了方法 getName,getAdress 与RPC接口 com.idle.test.openService@getInfo~II 之间的映射关系。
图6 方法链路获取
四、流量录制
在实际使用中我们采用流量录制平台进行流量录制,通过接口调用获取前 N 天的流量,具体规则可配置,由于流量本身是非线性的,部分流量可能很大,所以我们通过调度平台从应用的纬度出发,进行任务调度定时执行,保证流量及时更新,覆盖更多小流量接口,具体流程图如图5所示。只不过此时录制的流量是线上流量,而不是预发流量,但是整体流程一致,并且录制的 HTTP 及 RPC 接口也是一致的。录制的流量作为用例保存在数据库,比如在线上环境我们录制了RPC 接口 com.idle.test.openService@getInfo~II 的流量,那么就可以建立RPC 接口com.idle.test.openService@getInfo~II 与流量之间的映射关系,落库到数据库时流量是以流量 id 进行保存,否则数据量过大不便处理。
五、用例关联
在代码差异化分析之后我们已经获取了变动的方法名,经过调用链路的分析,我们建立了变动的方法和HTTP或者RPC接口的映射关系,那么如何将其与用例进行关联?我们通过流量录制平台录制线上流量,建立HTTP或者RPC接口同流量数据之间的映射关系,继而建立了变动的方法同流量用例之间的映射关系。具体而言,首先我们会积累各个应用 HTTP 及 RPC 的线上流量信息,建立HTTP及RPC接口同流量之间的关系,同时将对应接口的方法链路信息解析后保存在数据库,此时建立了HTTP或者RPC入口同接口调用过程中的方法之间的关联;代码发生变动后,我们可以获取变动的方法名,从上面的映射关系可以推断根据方法名可以找到对应的流量用例。
当项目提测时,会根据应用及应用开发分支获取变动方法,继而查询到对应的HTTP及RPC方法,之后自然就获得了服务端的流量数据,就可以触发用例回归。整个过程中可以清晰地看到影响的接口,并且可以执行对应的用例,通过影响的接口可以评估影响范围,做到心中有数,而不是强依赖开发同学的判断,从而对接口变更风险有了准确的评估。
六、效果及展望
在未采用精准测试服务之前,服务端接口发生变更之后,我们采用全量回归方式,按照每个应用每天提交n次,N个核心应用,以一周的时间计算,单次回归时间是M,M一般是在几分钟左右,那么总体的用例回归时间是MNn7,并且并不具备精准性;通过代码精准分析之后不必采用全量回归的方式,只要针对性进行回归即可,单次接口回归时间假设为K,K一般是小于一分钟,以一周为维度计算,总体的接口回归时间:KNn7,那么相比未采用精准测试服务之前总体耗费的时间大大降低。
精准测试是服务端接口测试的进一步延伸,除了应用于接口测试之外,本身积累的大量数据,比如代码提交记录,变动的方法,流量的分布,方法链路的变动等可以为后续项目风险评估,整体质量预测,业务服务监控等提供支持,并且可以作为一项基础服务为其他的测试能力提供支撑。