本文首发于微信公众号“Shopee技能团队”

1. 布景

跟着项目不断深入迭代,事务逻辑以及用户场景日渐复杂,弥补和维护单元测验维护的本钱也变得越来越高。测验掩盖质量经过测验用例评审或者人工 Code Review 的方式费时吃力,单凭多方交流和经验累积的方法,往往不行准确,也难以避免开发人员存在在代码上线前“夹藏私货”的场景,并且没有量化的、直观的客观数据来支撑。

为了在有限的时间及人力本钱内确保项目质量,完结对项目质量的精细化办理,咱们研发了 Finder —— 全栈代码测验掩盖率及用例发现体系(下文简称 Finder),经过准确化的数据量化代码质量,然后完结精准化测验。本文将介绍 Finder 的全体架构,以及它作为质量保障体系中的重要一环,如安在项目中完结准确化测验。

2. Finder 项目介绍

Finder 首要分为两个模块,一个是测验进程中对代码测验掩盖率进行收集与核算,一个是剖析代码和用例的映射联系,精准确认回归测验规模

代码测验掩盖率核算模块,能够满意多环境、多需求、多服务的复杂测验场景,实时收集测验进程中的掩盖率信息,并生成掩盖率核算陈述;其支撑多端语言接入(Web、React Native、Golang),完结前后端项目全掩盖,打通全体研发流程。

相关用例发现模块,针对变化的代码剖析函数调用联系,追溯完好的调用联系链路,符号出所影响的 API 接口及相关用例,确认测验回归规模。

3. 架构设计

Finder 分为署理层、使用层、中心服务层三个模块:

  • 署理层 Finder Agent,担任前期数据收集的作业,包含编译阶段的代码插桩、掩盖率数据的收集、解析源码函数调用联系信息等;
  • 使用层 Finder Platform,包含需求信息办理、分支信息办理、单文件掩盖率染色图展现、API 信息展现、测验用例相关、函数调用链展现等页面模块;
  • 中心服务层 Finder Server,其间,掩盖率剖析和服务调用剖析是最首要的两个模块:

    • 掩盖率剖析,对收集到的掩盖率数据进行数据聚合、差异增量剖析、数据批改等操作;
    • 服务调用剖析,将源码解析东西传输来的数据进行数据结构转化后,完结调用拓扑图生成、API 信息相关、测验用例发现等操作。

在前期完结数据收集的接入作业后,测验人员无需额定操作,正常进行事务测验,测验完结后能够在可视化平台中检查掩盖率数据、相关测验用例等信息。

4. 完结计划

4.1 代码测验掩盖率模块

代码掩盖率模块首要分为两个进程,第一步是经过对项目源码插桩,收集掩盖率信息;第二步是对掩盖率信息进行剖析,经过可视化平台展现核算陈述

进程一:插桩与数据收集

代码插桩,意为在程序中刺进一些代码,用于盯梢被测程序的某些信息。对于掩盖率测验而言,插桩的目的是检测程序中可履行句子被履行(即被掩盖)的状况。

Finder 支撑 JS 和 Golang 两种程序语言的代码掩盖率核算,接入本钱低,对事务需求无侵入性。

  • 对于 JS 程序,咱们在 babel 编译阶段进行插桩操作,注入到全局对象 window 中。咱们供给了上报掩盖率数据的 npm 包 —— coverage-report,前端使用接入后会主动上报数据到 Finder Server;
  • Golang 程序的掩盖率接入对事务项目零侵入,只需求引进 Finder Agent —— 掩盖率收集东西:它在编译阶段对源码插桩,包含 Git 信息和掩盖率信息注入;插桩完结后的服务会发动一个核算掩盖率的 Http Server,Finder Server 经过该 Http Server 供给的接口定时请求掩盖率数据。

进程二:差异掩盖率核算

比起全量代码的掩盖率,实践上咱们更关心改动代码部分的掩盖率状况。能够经过 Git 指令比照功用分支与 master 分支的代码差异,过滤无关代码,只针对改动代码部分进行掩盖率核算。

为完结差异掩盖率的核算,咱们约好以行(line)作为维度的结构表明 Git 代码差异和掩盖率信息,满意两者一一对应的联系。

首要将 Git 分支比照得到的 Diff 数据转化成以代码行作为索引的数组格局,元素的值有空值和 + 两种枚举值

  • 空值代表没有改动;
  • + 代表有改动。

掩盖率数组也转化成以代码行作为索引的数组格局,元素的值有 -1、0、1 三种枚举值:

  • -1 代表无需核算掩盖率的代码(例如空格,注释等);
  • 0 代表未掩盖的代码(没有履行);
  • 1 代表已掩盖的代码(已被履行)。

将 Diff 数据与掩盖率数组进行兼并,将非改动代码的掩盖率值置为 -1 。得到终究的差异掩盖率数据。

关键问题一:数据源标准化

因为不同程序语言上报的掩盖率数据结构都不共同,咱们需求将数据源标准化,一致转化以行(line)为维度的数组结构

首要,前端使用上报的掩盖率数据包含三种维度的掩盖率数据:

  • Statement Coverage:句子维度的掩盖率数据;
  • Branch Coverage:条件维度的掩盖率数据,例如 if/else、switch、三元运算符等;
  • Function Coverage:函数维度的掩盖率数据。

对于这三类掩盖率,咱们做出以下数据转化:

咱们选用与操作将三类掩盖率数据兼并为行掩盖率,即一行代码满意三类掩盖率才算被履行过。

而后端 Golang 服务收集的掩盖率数据,如下图。

同样,咱们也需求将其转化为行维度的数组结构。

关键问题二:确保代码改变后的掩盖率正确性

在集成测验的进程中,开发人员不可避免地会进行代码更新。当代码更新后,咱们希望能够记载新代码改动掩盖率的一起,依然保持原有代码的掩盖率数据。所以咱们需求获取新旧提交之间的代码差异,对原有掩盖率数据进行“批改”操作:

对原有的掩盖率数据,先删去 diff 成果中被移除的代码对应的掩盖率数据,再刺进 diff 成果中新增的代码对应的掩盖率数据。

举个比如:

比照初次提交 commit 1 和 master 分支,得到初次改动:新增三行代码。

符号这三行代码的行索引 3、4、8,并核算它们的掩盖率。

比照 commit 1 和 commit 2,得到两次提交之间的改动:删去之前两行代码,新增一行代码。

移除原数据中第 3、4 行数据,然后刺进新改动代码的行索引 7(删去后的索引位置)并核算新改动的掩盖率。

批改后的成果和 commit 2 与 master 分支比照的成果共同,既保留了初次改动的掩盖率数据,也记载了新改动的掩盖率数据。

关键问题三:单环境的代码掩盖率收集

在实践开发流程中,研发环境只要一套,咱们往往不能独占它,一切周版别需求都在 staging 环境开发,在 test 环境测验。这样会呈现一个问题:因为这种单一环境的测验流程,导致核算出来的掩盖率无法区分来自哪个详细功用分支,进而影响对各功用需求的测验规模判断。

为了处理这个问题,咱们提出两个计划:

第一个计划是树立多泳道研发环境,经过 PFB(Per Feature Branch)的形式对各需求开发环境进行阻隔。PFB 是一个能够快速树立虚拟环境的东西。它支撑将多个功用分支版别一起布置在同一个测验环境中,且每个功用分支可具有独自的流量拜访,然后完结不同的功用分支可具有相对阻隔的虚拟环境。

可是因为这个架构改动较大,间隔落地到项目中还需一段时间,因此第二个计划应运而生:咱们对单一的集成分支进行功用追溯,判别出变化代码是归于兼并进来的哪一个功用分支,并进行分类展现

  • 经过 Git Blame 指令从集成分支中判别出到各行代码对应的 commit hash;
  • 经过 Git Branch 指令查找 commit hash 来自哪一个功用分支。

经过以上两步寻找到每行代码与功用分支的对应联系,与掩盖率成果进行映射后可得出对单一集成分支的功用追溯作用,处理单环境的代码掩盖率收集问题。

4.2 相关用例发现模块

相关用例发现模块的关键是经过追溯变化代码的调用联系链,确认测验回归规模。这个进程首要分为两个阶段:源码解析阶段数据剖析阶段

进程一:源码解析

咱们在 Gitlab CI 接入源码解析东西,当有新代码提交时,触发源码解析。

经过对笼统语法树 AST 和中心转化代码 SSA 进行解析,得到以下数据:

  • 项目 Git 信息
  • 函数基本信息
  • 函数调用联系
  • RPC 调用信息
  • API 信息

最终将这些数据都打包一致发送到 Finder 服务端。

进程二:数据剖析

Finder 服务端接收到解析数据后,进行差异增量代码的函数调用联系全链路追溯,最终符号出相关的 API 信息及测验用例。详细追溯流程如下:

  1. Git Diff 得到功用分支与 Master 分支比照的代码改动;
  2. 经过差异增量代码的地点行数,确认所属函数体,进入进程 3;
  3. 追溯指定函数的调用联系,直到寻找到 API 触发函数;
  4. 若遇到 RPC 调用的状况,进行 RPC 调用联系追溯,找到 RPC 调用方函数,继续回到进程 3 的操作;
  5. 追溯作业完结,得到从变化函数到 API 触发函数的调用联系全链路;
  6. 经过以上得到的 API 触发函数,符号相关的 API 信息及测验用例。

每次代码改变都会触发上述流程,得到最新的函数调用链路信息,在可视化前台中展现该功用分支的变化函数调用联系链,以及相关测验用例。

关键问题:后端微服务架构串联,全链路掩盖

目前咱们后端服务选用了分布式的微服务架构,例如一个购买产品的流程,当用户进入 APP 浏览产品时,会发起请求经过网关层,转发到产品服务,然后在创立订单时会调起订单服务,订单服务再调用用户信息服务和促销服务,整个进程还会调用多个根底服务共同完结一次操作流程。

咱们希望除了解析服务内的调用联系外,也需求服务间的调用联系串联起来,得到完好的调用链路。

为了处理这个问题,咱们针对项目中的 RPC 调用联系进行静态解析,经过寻找调用方函数——RPC Command——被调用方函数三者的相相联系,对调用方函数和被调用方函数进行符号,当函数调用联系链追溯到被调用方函数时,匹配到其对应的调用方函数,继续向上追溯,然后得到服务间的完好调用联系链路。

5. 实践使用

Finder 经过接入团队中的项目流程办理体系,在整个需求生命周期的各个环节发挥着不同的作用。

5.1 提测阶段

5.1.1 掩盖率提测合格

开发人员必须到达规定的掩盖率标准才能提测,对于掩盖率未合格的状况,开发人员需求反推代码逻辑是否存在问题,进一步剖析前期技能计划设计不行合理,仍是对技能计划的完结有误,或者是在完结进程中造成的策略性抛弃等。

5.1.2 掩盖率定制化

针对不同项目会有定制化的掩盖率要求,支撑配置需求疏忽核算掩盖率的文件类型以及目录。

对于移动端使用,供给 iOS 和 Android 双平台的掩盖率数据核算,这样能够提早露出移动端的兼容性问题,确保提测交付质量。

5.2 测验阶段

5.2.1 掩盖率实时剖析

测验人员介入测验后能够在 Finder 平台上实时检查掩盖率剖析成果,了解该测验版别改变代码的测验掩盖状况。

5.2.2 掩盖率染色图

经过代码掩盖率染色图辅佐整个测验进程,便利测验人员对测验用例进行查漏补缺,尽可能确保一切关键场景都能掩盖到;一起能够驱动测验人员加强对代码的理解,充分把控代码质量。

5.2.3 需求维度掩盖率核算

经过相关项目办理体系,从需求级别的角度,供给该需求下各模块的掩盖率数据,包含不同的后端服务和前端使用,辅佐测验人员做决策,衡量质量风险。

5.3 回归阶段

符号改变规模

根据代码改变规模推断出函数改变规模,进一步符号出相关测验用例,然后完结用例和代码的相相联系。

用例发现剖析陈述中会符号出该需求改变部分的相关信息,包含改变的函数调用联系链路和受影响的 API 接口,测验人员从中能够快速确认回归测验规模,经过更小的维度更精准地衡量测验质量,针对性进行自动化/手艺测验,极大减少回归阶段的作业量,以较小的回归本钱确保较高的测验质量。

6. 未来展望

Finder 作为项目中质量保障体系中的一环,目前还处于初级阶段。在未来咱们会继续寻找 Finder 在研测协同体系中的更优实践。

1)支撑更多维度的掩盖率数据核算

咱们希望在核算方面能够供给更产品化更精细化的数据,包含关键字掩盖率、相关代码掩盖率、高风险掩盖率等,能够更好地辅佐测验人员做决策。

2)精准记载 Bug 轨道

后续咱们计划支撑经过以添加符号的形式独自核算掩盖率,经过记载 bug 的完好代码轨道,复原问题的复现路径,准确认位问题地点。

3)树立用例知识库

构建用例与代码映射联系,形成用例知识库,支撑对代码和用例进行相关办理,准确引荐改动代码相关的用例,供给测验用例优化主张。

本文作者

Hao、Qianguang,前端工程师,来自 Shopee Digital Purchase 团队。