Finder通过接入团队中的项目流程管理系统,在整个需求生命周期的各个环节发挥着不同的作用。
测试人员介入测试后可以在Finder平台上实时查看覆盖率分析结果,了解该测试版本变更代码的测试覆盖情况。
举个例子:
关键问题:后端微服务架构串联,全链路覆盖
步骤源码解析
未来展望
同样,我们也需要将其转换为行维度的数组结构。
精准记录Bug轨迹
通过GitBlame命令从集成分支中判别出到各行代码对应的commithash;通过GitBranch命令查找commithash来自哪一个功能分支。
根据代码变更范围推断出函数变更范围,进一步标记出相关测试用例,从而实现用例和代码的关联关系。
通过以上两步寻找到每行代码与功能分支的对应关系,与覆盖率结果进行映射后可得出对单一集成分支的功能追溯效果,解决单环境的代码覆盖率采集问题。
3回归阶段
步骤插桩与数据采集
-1代表无需统计覆盖率的代码;0代表未覆盖的代码;1代表已覆盖的代码。
标记这三行代码的行索引并统计它们的覆盖率。
将Diff数据与覆盖率数组进行合并,将非改动代码的覆盖率值置为-得到最终的差异覆盖率数据。
覆盖率数组也转换成以代码行作为索引的数组格式,元素的值有-0、1三种枚举值:
2相关用例发现模块
用例发现分析报告中会标记出该需求变更部分的相关信息,包括变更的函数调用关系链路和受影响的API接口,测试人员从中可以快速确定回归测试范围,通过更小的维度更精准地度量测试质量,针对性进行自动化/手工测试,极大减少回归阶段的工作量,以较小的回归成本保证较高的测试质量。
第一个方案是搭建多泳道研发环境,通过PFB的形式对各需求开发环境进行隔离。PFB是一个可以快速搭建虚拟环境的工具。它支持将多个功能分支版本同时部署在同一个测试环境中,且每个功能分支可拥有单独的流量访问,从而实现不同的功能分支可拥有相对隔离的虚拟环境。
代理层FinderAgent,负责前期数据采集的工作,包括编译阶段的代码插桩、覆盖率数据的采集、解析源码函数调用关系信息等;应用层FinderPlatform,包含需求信息管理、分支信息管理、单文件覆盖率染色展示、API信息展示、测试用例关联、函数调用链展示等页面模块;核心服务层FinderServer,其中,覆盖率分析和服务调用分析是最主要的两个模块:覆盖率分析,对收集到的覆盖率数据进行数据聚合、差异增量分析、数据修正等操作;服务调用分析,将源码解析工具传输来的数据进行数据结构转换后,完成调用拓扑生成、API信息关联、测试用例发现等操作。
首先将Git分支对比得到的Diff数据转换成以代码行作为索引的数组格式,元素的值有空值和+两种枚举值:
空值代表没有改动;+代表有改动。
2覆盖率定制化
对于这三类覆盖率,我们做出以下数据转换:
开发人员必须达到规定的覆盖率标准才能提测,对于覆盖率未达标的情况,开发人员需要反推代码逻辑是否存在问题,进一步分析前期技术方案设计不够合理,还是对技术方案的实现有误,或者是在实现过程中造成的策略性放弃等。
对比commit1和commit得到两次提交之间的改动:删除之前两行代码,新增一行代码。
2覆盖率染色
步骤数据分析
1提测阶段
代码测试覆盖率统计模块,能够满足多环境、多需求、多服务的复杂测试场景,实时收集测试过程中的覆盖率信息,并生成覆盖率统计报告;其支持多端语言接入,实现前后端项目全覆盖,打通整体研发流程。
最后将这些数据都打包统一发送到Finder服务端。
通过关联项目管理系统,从需求级别的角度,提供该需求下各模块的覆盖率数据,包括不同的后端服务和前端应用,辅助测试人员做决策,衡量质量风险。
架构设计
1覆盖率实时分析
项目Git信息函数基本信息函数调用关系RPC调用信息API信息
后续我们打算支持通过以添加标记的形式单独统计覆盖率,通过记录bug的完整代码轨迹,还原问题的复现路径,精确定位问题所在。
StatementCoverage:语句维度的覆盖率数据;BranchCoverage:条件维度的覆盖率数据,例如if/else、switch、三元运算符等;FunctionCoverage:函数维度的覆盖率数据。
建立用例知识库
前端应用上报的覆盖率数据包含三种维度的覆盖率数据:
但是由于这个架构改动较大,距离落地到项目中还需一段时间,因此第二个方案应运而生:我们对单一的集成分支进行功能追溯,判别出变动代码是属于合并进来的哪一个功能分支,并进行分类展示。
在实际开发流程中,研发环境只有一套,我们往往不能独占它,所有周版本需求都在staging环境开发,在test环境测试。这样会出现一个问题:由于这种单一环境的测试流程,导致统计出来的覆盖率无法区分来自哪个具体功能分支,进而影响对各功能需求的测试范围判断。
由于不同程序语言上报的覆盖率数据结构都不一致,我们需要将数据源标准化,统一转化以行为维度的数组结构。
通过代码覆盖率染色辅助整个测试过程,方便测试人员对测试用例进行查漏补缺,尽可能保证所有关键场景都能覆盖到;同时可以驱动测试人员加强对代码的理解,充分把控代码质量。
步骤差异覆盖率统计
代码覆盖率模块主要分为两个步骤,第一步是通过对项目源码插桩,采集覆盖率信息;第二步是对覆盖率信息进行分析,通过可视化平台展示统计报告。
相关用例发现模块,针对变动的代码分析函数调用关系,追溯完整的调用关系链路,标记出所影响的API接口及相关用例,确定测试回归范围。
实现方案
实践应用
GitDiff得到功能分支与Master分支对比的代码改动;通过差异增量代码的所在行数,确定所属函数体,进入步骤3;追溯指定函数的调用关系,直到寻找到API触发函数;若遇到RPC调用的情况,进行RPC调用关系追溯,找到RPC调用方函数,继续回到步骤3的操作;追溯工作完成,得到从变动函数到API触发函数的调用关系全链路;通过以上得到的API触发函数,标记相关的API信息及测试用例。
通过对抽象语法树AST和中间转换代码SSA进行解析,得到以下数据:
移除原数据中第4行数据,然后插入新改动代码的行索引7并统计新改动的覆盖率。
对于JS程序,我们在babel编译阶段进行插桩操作,注入到全局对象window中。我们提供了上报覆盖率数据的npm包——coverage-report,前端应用接入后会主动上报数据到FinderServer;Golang程序的覆盖率接入对业务项目零侵入,只需要引入FinderAgent——覆盖率收集工具:它在编译阶段对源码插桩,包括Git信息和覆盖率信息注入;插桩完成后的服务会启动一个统计覆盖率的HttpServer,FinderServer通过该HttpServer提供的接口定时请求覆盖率数据。
关键问题单环境的代码覆盖率采集
修正后的结果和commit2与master分支对比的结果一致,既保留了首次改动的覆盖率数据,也记录了新改动的覆盖率数据。
标记变更范围
1覆盖率提测达标
在前期完成数据采集的接入工作后,测试人员无需额外操作,正常进行业务测试,测试完成后可以在可视化平台中查看覆盖率数据、相关测试用例等信息。
Finder分为代理层、应用层、核心服务层三个模块:
本文作者Hao、Qianguang,前端工程师,来自ShopeeDigitalPurchase团队。
为了解决这个问题,我们提出两个方案:
我们采用与操作将三类覆盖率数据合并为行覆盖率,即一行代码满足三类覆盖率才算被执行过。
Finder服务端接收到解析数据后,进行差异增量代码的函数调用关系全链路追溯,最后标记出相关的API信息及测试用例。具体追溯流程如下:
关键问题确保代码变更后的覆盖率正确性
支持更多维度的覆盖率数据统计
对原有的覆盖率数据,先删除diff结果中被移除的代码对应的覆盖率数据,再插入diff结果中新增的代码对应的覆盖率数据。
Finder支持JS和Golang两种程序语言的代码覆盖率统计,接入成本低,对业务需求无侵入性。
对比首次提交commit1和master分支,得到首次改动:新增三行代码。
比起全量代码的覆盖率,实际上我们更关心改动代码部分的覆盖率情况。可以通过Git指令对比功能分支与master分支的代码差异,过滤无关代码,只针对改动代码部分进行覆盖率统计。
2测试阶段
相关用例发现模块的关键是通过追溯变动代码的调用关系链,确定测试回归范围。这个过程主要分为两个阶段:源码解析阶段和数据分析阶段。
关键问题数据源标准化
Finder作为项目中质量保障体系中的一环,目前还处于初级阶段。在未来我们会持续寻找Finder在研测协同体系中的更优实践。
为了解决这个问题,我们针对项目中的RPC调用关系进行静态解析,通过寻找调用方函数——RPCCommand——被调用方函数三者的关联关系,对调用方函数和被调用方函数进行标记,当函数调用关系链追溯到被调用方函数时,匹配到其对应的调用方函数,继续向上追溯,从而得到服务间的完整调用关系链路。
3需求维度覆盖率统计
对于移动端应用,提供iOS和Android双平台的覆盖率数据统计,这样能够提前暴露移动端的兼容性问题,保证提测交付质量。
目前我们后端服务采用了分布式的微服务架构,例如一个购买商品的流程,当用户进入APP浏览商品时,会发起请求经过网关层,转发到商品服务,然后在创建订单时会调起订单服务,订单服务再调用用户信息服务和促销服务,整个过程还会调用多个基础服务共同完成一次操作流程。
代码插桩,意为在程序中插入一些代码,用于跟踪被测程序的某些信息。对于覆盖率测试而言,插桩的目的是检测程序中可执行语句被执行的情况。
而后端Golang服务采集的覆盖率数据,如下。
为实现差异覆盖率的计算,我们约定以行作为维度的结构表示Git代码差异和覆盖率信息,满足两者一一对应的关系。
1代码测试覆盖率模块
Finder主要分为两个模块,一个是测试过程中对代码测试覆盖率进行收集与统计,一个是分析代码和用例的映射关系,精准确定回归测试范围。
每次代码变更都会触发上述流程,得到最新的函数调用链路信息,在可视化前台中展示该功能分支的变动函数调用关系链,以及相关测试用例。
我们在GitlabCI接入源码解析工具,当有新代码提交时,触发源码解析。
文章为作者独立观点,不代表股票交易接口观点