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

背景

随着业务增长, 随之而来的前端需求激增, 如何在有限的时间内保证前端代码的质量.
通过测试同学单方面的保障, 还是免不了前端线上问题, 存在回归不到位或者测试遗漏的地方, 同时测试质量的高低没有客观数据可量化.

通过单测方法补充, 可以提前发现一部分问题, 减少问题解决的成本, 但是由于业务形态的原因, 需求变更频繁, 功能迭代快, 补充和维护单测的成本比较高, 在业务方的大部分前端工程中暂时没有单测方法, 因此开发在自测时, 感知比较薄弱, 无量化数据, 在项目提测前也没有统一指标可以把关, 测试对开发的自测状况也不了解;

同时前端缺少像jacoco这样的集成测试覆盖率统计框架, 无法通过集成测试收集覆盖率, 对于测试阶段的质量仍然没有数据量化
结合上面说的几点, 我们提出了前端集成测试覆盖率统计工具的需要, 以此来提升开发自测质量以及项目提测质量, 同时帮助补充回归不到位或测试遗漏的场景, 提升上线质量.


技术选型

首先, 覆盖率收集的前提, 需要完成代码插桩工作, 插桩方法来自于两个开源覆盖率统计框架, istanbul.js以及istanbul-middleware (以下称im) , 提供了若干个插桩方法, 而im其实也是在istanbul.js的基础上做了封装, 能力来自于istanbul-lib-instrument
所有的插桩方法, 大致分为两种类型 —— 1、运行前插桩 2、运行时插桩

运行前插桩

nyc instrument

针对编译之后的JS文件 , 进行手动插桩 , 形成插桩后的新JS文件


babel-plugin-istanbul

istanbul提供的babel插件 , 能够在代码编译打包阶段直接植入插桩代码
适用于使用babel的前端工程,基于react和vue的工程都可以

运行时插桩

im.hookLoader

适用于服务端的文件挂载 比如node应用
当应用启动时 , 会在require入口处添加hook方法 , 使得应用启动时加载到的都是插桩后的代码


im.createClientHandler

适用于客户端的JS挂载 ,比如react和vue的js
通过指定root路径,会把所有该路径的js文件请求拦截,返回插桩后的代码,即浏览器请求静态资源的动作
效果与babel-plugin-istanbul类似,区别在于该方法是在浏览器请求js时才会返回插桩代码,是一个动态过程

插桩方式 功能 优势 劣势
nyc 本地手动插桩源js文件, 生成插桩后文件 编译后的js都可手动插桩, 不限工程框架 手动插桩后的文件需要自己上传, 对原打包发布流程有影响; 不适用于服务端插桩
babel-plugin-istanbul 在babel编译时 , 自动生成插桩代码 改造成本低 , 自动插桩快捷 限定于使用babel的工程
im.hookLoader require入口处添加钩子方法,返回已插桩代码 改造成本低 , 自动插桩快捷 仅适用于服务端插桩
im.createClientHandler 拦截浏览器请求静态资源文件的GET方法, 返回插桩后的JS 自动插桩 , 无须改造原打包流程和脚本 仅适用于客户端插桩; 该方法基于express, 限定于使用express的工程

最后我们所使用的插桩方法
App(node)—— istanbulMiddleware.hookLoader
Client(react & vue)—— babel-plugin-istanbul


模块设计


主要分为三个模块 , 先通过代码插桩获得可追踪的代码 , 然后实时上报用户行为产生的代码行覆盖记录 , 最后呈现覆盖率相关信息.

代码插桩


Client端
使用babel-plugin-istanbul插件, 在babel编译阶段即可完成

Node端

依赖istanbuljs提供的能力 - istanbul-lib-hook 、istanbul-lib-instrument
重写istanbulMiddleware.hookLoader方法 , node启动前挂载文件 , 会在require方法前增加钩子函数, 增加代码插桩

插桩结果举例

被插桩的JS 会新增一个coverage方法, 维护并指向覆盖率信息归属, 并用来获取该文件的覆盖率信息
同时该js中的方法在执行过程的路径上会留下标记, 被执行到之后实时更新覆盖率信息中相对应的行或者块信息

数据上报


Node端
应用发布时 , 写入对应的工程和分支信息 , 创建定时器 , 实时上传_global.coverage变量 , 即覆盖率信息


Client端
客户端的上报比较特殊 , 客户端不像服务端 , 在发布后可以全局保持coverage变量以及定时器方法 , client端所有的数据生成和消耗都跟随页面的生命周期 , 所以不太可控 , 因此需要一个额外容器进行处理 , 我们选择了通过chrome插件来上报 , 通过全局管理覆盖率信息对象 , 以及通知下发来实现上报流程 . 该插件详细的工作流程如下

覆盖率服务端

  • 继承istanbul middleware的功能
  • 支持分支维度接收和查询覆盖率
  • 代码变更时覆盖率替换, 支持存储和查看历史版本

主要基于istanbul-middleware做了二次开发 , 扩展了istanbulMiddleware.createHandler方法

/:ns/:repo /:ns/:repo/show
两个覆盖率展示接口 新增了ns、repo、branch三个入参, 用来区别不同的覆盖率
同时增加额外参数history 传入该变量 标志获取的是历史覆盖率

/client/:ns/:repo?branch={}&source={} body携带覆盖率信息
根据应用和分支信息上报 接收到上报信息之后 会先获取该分支下的已有覆盖率 然后和此次上报的信息做合并
合并是根据文件名字遍历合并的 如果发现某个文件 新旧两份覆盖率结构不同
即发生了代码变更 则会丢弃旧的覆盖率 以新覆盖率为准 同时把旧的覆盖率存储到历史版本中

页面展示


全量覆盖率展示
使用istanbulmiddle原生报告生成

增量覆盖率展示

通过gitlab接口对比master差异 , 分文件展示各自的覆盖率 , 同全量覆盖率 , 只是细化了 , 整体页面用vue + muse-ui完成


工作流程

主要分为3部分 , 对应上一节说的接入 、上报 、展示
通过babel插件完成客户端代码插桩 , 提供给node端使用的插桩插件 , 可以一步完成服务端的代码插桩以及定时上报功能
配合提供的chrome插件 , 完成客户端的覆盖率上报任务
覆盖率服务端负责信息的接收和存储 , 并返回给前端数据信息
前端负责数据信息展示


业务实践

接入测试环境发布平台, 实现以应用和分支维度的多版本实时覆盖率收集和展示功能 , 无缝对接项目测试环境 , 项目中各应用发布后 , 自动开启覆盖率上报 , 在项目测试过程中实时记录 , 可实时查看. 在项目提测前 , 给予开发量化指标 , 项目测试结束后可以给出最终覆盖率数据 , 帮助测试同学检查以及完善未覆盖的功能.

目前在电商教育和行业两条业务线中已有接入,由于该工具限制在qa环境使用 , 仅限收集在qa环境测试的项目数据. 在功能测试阶段,从使用数据上来看 , 增量行代码覆盖率达到80%以上(目前的增量只到文件维度 , 未到行维度), 未覆盖的行主要包括四种: 异常捕获、防御性编码、非本次新增无需关心的代码以冗余代码 , 属于可允许的范围.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容