天天看点

技术干货 | 网易云商前端精准测试开发实践

作者:163企业邮箱
技术干货 | 网易云商前端精准测试开发实践

导读:网易云商在开发测试过程中,遇到了一系列的问题。为了解决这些问题,网易云商开发了一套前端精准测试工具,该工具已在多个项目中落地,本文将基于云商的落地实践,分享该方案开发的思路与实际效果。

技术干货 | 网易云商前端精准测试开发实践

文 | 邱瑶瑶

网易云商

技术干货 | 网易云商前端精准测试开发实践

背景

什么是精准测试?精准测试是通过一系列技术手段,对测试过程产生的数据采集、存储、计算、汇总,并进行可视化、分析、改进与优化。为什么要做前端精准测试?在目前网易云商的开发测试过程中,面临以下问题:

  • 系统复杂度高:随着业务发展,自身应用代码复杂度会不断增加,前端⼿⼯⿊盒测试覆盖度低,成本⾼,如何准确、全面判定代码修改影响范围会越来越重要。
  • 需求迭代快:随着敏捷开发在项目中的推进,测试时间也被缩短,测试范围需要开发测试人员根据代码和业务熟悉程度精确把控。
  • 业务组件化:为了提升代码复用性,开发同学一般会将代码功能抽象成组件,经常发生因为修改一个组件或者公共方法没有回归到其修改影响而引起的 bug,但单元测试在业务代码变更频繁的情况下难以推行。因此需要通过前端精准方案及相应工具,准确判断前端代码影响的范围,以及需要有可信的数字化指标来衡量前端测试的效果,做到前端测试精准化、可信化。
技术干货 | 网易云商前端精准测试开发实践

业内方案

目前,针对前端精准测试,业内许多公司都有所实践,包括 VIVO 马可平台、猫眼、Shopee、有赞等,这些方案大多聚焦于代码覆盖率这个维度来度量测试的情况,缺乏对代码影响范围的评估。

优势 劣势 平台介绍
VIVO马可平台
  • 不挑业务框架,一键接入
  • 支持代码覆盖率报告、增量覆盖率报告
  • 支持多个用户实时合并与查看
缺少影响范围评估

Vivo马可平台

https://www.cnblogs.com/vivotech/p/15783555.html

猫眼
  • 支持多端:PC端、移动端、客户端、小程序
  • 支持覆盖率增量报告
  • 支持多用户报告合并
缺少影响范围评估

猫眼前端代码覆盖率工具

https://juejin.cn/post/6974294579981844516

Shopee
  • 支持多端语言接入(web 、react native、 golang)
  • 通过追溯变动代码的调用关系链,确定测试回归范围
缺少前端代码的调用关系链

全栈代码测试覆盖率及用例发现系统的建设和实践

https://zhuanlan.zhihu.com/p/535884029

有赞
  • 可用户自己控制上报护具
  • 支持多用户报告合并
缺乏影响范围的合理评估

前端精准测试探索:覆盖率实时统计工具

https://tech.youzan.com/front-coverage/

技术干货 | 网易云商前端精准测试开发实践

方案与架构

  • 解决“我要测什么”:我们通过代码修改所影响文件和影响路由,作为前端精准测试的范围推荐,帮助开发、测试同学明确测试内容,解决“我要测什么”的问题,实现测试精准化。
  • 解决“我测的怎么样”:通过组件覆盖率、路由覆盖率、代码覆盖率这三大维度作为前端测试覆盖程度分析的依据,解决“我测的怎么样”问题,实现测试可信化。
技术干货 | 网易云商前端精准测试开发实践

本方案的整体设计结构如下所示:

技术干货 | 网易云商前端精准测试开发实践
技术干货 | 网易云商前端精准测试开发实践

获取代码修改影响范围

代码文件依赖关系获取

要获取代码修改影响范围,前提是获取代码中文件依赖关系。文件依赖获取方案对比如下:

技术干货 | 网易云商前端精准测试开发实践

基于解析时长和灵活性的考虑,最终选择自行开发,基于 babel 获取源码的 AST 信息,获取源码的依赖关系。

代码修改影响范围方案主要分成三个部分:

  • 第一部分:通过 simpleGit 获取修改文件的 diff 数据。
  • 第二部分:文件依赖解析模块,根据配置的入口文件,解析源码的 AST,解析 import、export 等节点,获取文件依赖的关系。
  • 第三部分:根据 diff 信息和文件依赖关系获取代码修改所影响的文件及路由,并上报到服务器。
技术干货 | 网易云商前端精准测试开发实践

获取代码修改所影响路由数据。对于测试同学来说,更关心的数据是代码修改影响到了哪些路由,那么如何得知?我们需要知道以下信息:

1. 文件的依赖关系:

{
   file:"A.js",
   depedFiles:["B.js","C.js"]
}           

示例中表示 B.js 与 C.js 文件中引入了 A.js 文件。

文件的依赖关系可以构成一个有向图的结构,如下图所示:

技术干货 | 网易云商前端精准测试开发实践

2. 路由及路由根组件所对应的文件路径信息的映射关系:即某个路由下,对应的根组件的代码路径。

routes:[
    {
      "path": "/admin/a1",
      "componentPath": "G.js"
    },
    {
      "path": "/admin/b1",
      "componentPath": "H.js"
    }
  ]           

通过判断修改的文件与路由根组件所对应的文件之间是否存在路径,即可判断该文件的修改是否影响到了此路由。

路由映射关系的获取

路由映射关系如何获取?最简单的方式是在每个工程下面有一个配置文件,文件中配置每个路由对应的根组件的相对路径,例如上述映射关系所示例。

此方案简单且适配各类技术框架,不过存在以下问题:

  • 需要手动收集目前的路由及组件配置情况。
  • 以后写新路由的时候,都需要额外再写一份代码。

能不能有更加自动化的获取该映射关系配置的方法呢?

项目组的技术栈基本都是 react+react-router,在 Route(V4 及以上)等组件中,如下图所示,props 里中存在 path 及 component 数据,path 为配置的路由 url,component 对应着相关组件,即路由与组件的映射关系,是否可以通过什么方式命中这个路由,获取这两个信息,再生成整个项目的配置文件?

技术干货 | 网易云商前端精准测试开发实践

而且,目前 component 对象下只包含了组件函数的声明,并没有组件所在的代码路径,故我们需要额外在组件中注入代码路径这一信息。

由此,设计了以下方案:

  • 需要对每个 react 组件注入该组件所在的路径 effectFilePosition 的属性。
  • 在命中对应的路由组件时,上传该组件的路由信息 path 和位置信息 effectFilePosition 到本地的服务器,本地服务器会进行处理,在项目工程根目录下生成一个 ppeffect.json 文件,里面保存着路径和位置的映射关系。
技术干货 | 网易云商前端精准测试开发实践

对组件注入所在路径的属性

开发了 webpack-component-position-plugin 的 webpack 插件,注入该组件所在的路径 effectFilePosition 的属性。

function addPath(parser, node) {
  if (updatedNodes.has(node)) {
    return
  }
  const componentName = node.id.name
  const position = path.relative(process.cwd(),parser.state.current.resource)
  const dep = new ModuleAppenderDependency(`;try{${componentName}.effectFilePosition="${position}";}catch(e){}`, node.range)
  dep.loc = node.loc
  parser.state.current.addDependency(dep)
  updatedNodes.add(node)
}           

效果展示:

技术干货 | 网易云商前端精准测试开发实践

为路由组件添加上报功能

开发 pp-effect-router 包,提供 withEffectSwitch、withEffectRouter 等高阶方法,为 Route、Switch 等组件加上上报服务器功能。

技术干货 | 网易云商前端精准测试开发实践

自动为项目中的 Route、Switch 等组件加上上报的功能

在项目中一个个手动修改 Route 和 Switch 等方法是不现实的,代码侵入性也非常强,通过开发 babel 插件,自动为路由组件接入上报的功能。我们的诉求即需要把以下代码:

import { Route as ReactRoute, Switch, Redirect } from 'react-router';


const Route = (props)=>{
  //doSomething
  return <ReactRoute {...props}/>
}           

转换成:

import { withEffectSwitch, withEffectRouter } from "@ysf/pp-effect-router";
import { Route as EffectRoute, Switch as EffectSwitch, Redirect } from 'react-router';
const Switch = withEffectSwitch(EffectSwitch);
const ReactRoute = withEffectRouter(EffectRoute);           

通过开发 babel 插件 react-effect-import 实现以上功能,babel 插件配置方便,不需要该功能可不接入。

至此实现了只要访问相对应的路由,即可自动生成路由和文件位置信息的映射关系。

技术干货 | 网易云商前端精准测试开发实践

影响范围数据的上报

目前有三种情况会触发代码变更影响范围的数据计算与上报,分别是:

  • 本地提交代码 commit 时:通过配置 pre-commit 钩子触发 pp-effect 相关命令,在提交 commit 时,计算本次 commit 的代码变更影响,打印到终端中显示,为开发同学提供参考。
  • 触发 GITLAB CI/CD 任务:通过配置 CI/CD,提交代码后,执行 pp-effect 命令,将提交代码所在分支与 master 分支进行对比,计算本分支的代码变更影响,并推送给服务器。
  • 测试环境部署时触发任务:通过配置测试服部署文件,在部署测试环境时,执行 pp-effect 命令,将提交代码所在分支与 master 分支进行对比,计算本分支的代码变更影响,并推送给服务器。
技术干货 | 网易云商前端精准测试开发实践
技术干货 | 网易云商前端精准测试开发实践

组件覆盖率和路由覆盖率上报

在云商的前端精准测试方案中,我们开发了配套的 Chrome 插件,实现组件覆盖数据和路由覆盖数据的上报。

通过 Chrome 插件可快速查看某个分支所修改的文件、以及影响的路由等信息;列表可展示两种维度:分别是路由维度和文件维度。

  • 文件维度下,可以查看修改的文件影响到了哪些路由。
  • 路由维度下,可以看到该路由下都有哪些文件被修改。

两个维度切换方便测试同学把控测试。我们通过点击列表中的路由,即可跳转到对应页面,并触发路由覆盖率的上报;而通过点击文件,可触发该文件的覆盖率上报,由精准服务器记录与计算。

技术干货 | 网易云商前端精准测试开发实践
技术干货 | 网易云商前端精准测试开发实践
技术干货 | 网易云商前端精准测试开发实践

前端代码覆盖率方案设计

前端代码覆盖率整体方案

前端代码覆盖率方案整体分成以下 4 个部分:

技术干货 | 网易云商前端精准测试开发实践
  • 代码插桩:通过使用 babel-plugin-istanbul 的 babel 插件,对代码进行插桩。
  • 覆盖率上报:通过 webpack-effect-report-plugin 插件,在代码中注入工程名、分支、代码 diff 信息等,用户访问页面时,通过 pp-effect-report 定时向服务器上报覆盖率数据。
  • 覆盖率数据处理:node-effect 是一个 node 服务器,提供了覆盖率上报接口、覆盖率数据展示,使用 istanbul-lib-coverage 实现覆盖率数据合并,istanbul-lib-report 和 istanbul-reports 等实现覆盖率数据的展示,将覆盖率数据存储至精准平台服务器中。
  • 覆盖率数据展示:通过精准平台提供展示入口,调用 node 服务器提供的接口,展示覆盖率数据;

代码插桩

首先,要获取到代码覆盖率需要对代码进行插桩。那么,何为代码插桩呢?代码插桩指的是在保证被测程序原有逻辑完整性的基础上在程序中插入一些探针(又称为“探测仪”,本质上就是进行信息采集的代码段,可以是赋值语句或采集覆盖信息的函数调用)。插桩方法基本来自于两个开源覆盖率统计框架,istanbul.js 以及 istanbul-middleware ,这两个框架提供了若干个插桩方法。

由于云商项目都是使用了 babel,考虑选择 babel-plugin-istanbul babel 插件,进行编译插桩、改造成本低,由于仅在测试服使用,故包增大问题可以接受。

技术干货 | 网易云商前端精准测试开发实践

在工程中配置插件,在项目页面中,会注入一个全局变量__coverage__,即是覆盖率数据

技术干货 | 网易云商前端精准测试开发实践

覆盖率数据上报思考

目前,主流有两种形式的覆盖率上报方式,基于适用性和精确性等方面考虑,使用在项目中嵌入上报代码。

技术干货 | 网易云商前端精准测试开发实践

通过 webpack-effect-report-plugin 插件,将工程信息、分支信息等注入到项目中。

技术干货 | 网易云商前端精准测试开发实践

此外,通过 pp-effect-report 插件,定时上报覆盖率数据;在上报覆盖率数据的时候,会依据 diff 的信息,目前只上报修改的文件的覆盖率数据。

技术干货 | 网易云商前端精准测试开发实践

覆盖率处理服务器

技术干货 | 网易云商前端精准测试开发实践

覆盖率处理器提供两个接口:

  • 上报接口:根据分支 branch、工程名 projectName 等,先去覆盖率数据库中拉取覆盖率数据率,和上报的数据进行处理、合并,再存储至覆盖率数据库中。
  • 展示接口:根据所要展示的分支 branch、工程名 projectName,拉取相应的数据,通过 istanbul-lib-report 和 istanbul-reports 的处理,返回报告页面数据。

不过 istanbuljs 的覆盖率报告缺乏对代码 diff、增量代码、增量代码覆盖率相关的处理,从测试角度更在乎的是增量代码覆盖率的维度;需要进行一定的二次开发。

这里对 istanbul-reports 进行了二次开发,在上报数据时,标注了代码增量的行数,判断改增量行是否被覆盖,经过处理后,覆盖率数据 coverageMap 对象具有了两个新的属性,分别是 incrementStatementMap 和 incrementCoverdS,在后续 istanbul-reports 生成报告时通过解析这两个新增的属性,可以展示报告中行的新增情况和覆盖情况。

前面有➕加号代表为新增,加号但是有(x)代表新增未覆盖代码;

技术干货 | 网易云商前端精准测试开发实践
技术干货 | 网易云商前端精准测试开发实践

小结

通过以上前端精准测试工具及平台,从代码修改所影响的文件范围以及路由范围实现了对前端测试数据范围的推荐,通过对组件覆盖率、路由覆盖率以及代码增量覆盖率实现前端测试覆盖程度分析的度量。目前该工具已在智企的多个项目中落地,代码覆盖率方案仍处于初级阶段有待完善。前端精准测试平台未来也会从数据推送精准性、可用性、自动性等多个方面进行优化,寻找更优实践方案。

继续阅读