专栏文章 2019 年 我们打了几场硬仗 (上)

simple · 2020年04月23日 · 最后由 张彬彬 回复于 2022年05月11日 · 9078 次阅读
本帖已被设为精华帖!

前言

这段时间在 OKR 的驱使下,我们团队在业务测试和目标达成的路上专注的奔跑,战线拉的越来越长,担心积压的内容太多,走得太远而忽略了前进路上遇到的经验教训的归纳和沉淀。恰逢团队再次调整,借此机会来回顾一下从 2018 年团队下半年到 2019 年底,第一次调整后我们团队总共做了哪些事情,取得了什么样的进展,遇到了哪些坑。

专栏文章,写的比较随意。

导读

  1. 业务线梳理
  2. 目标设定
  3. 任务拆解
  4. 最有效果的任务 1:代码覆盖率体系
    • 增量代码覆盖率方案
    • 代码伪实时染色系统
  5. 最有效果的任务 2:模型算法监控体系
  6. 团队取得的落地效果
  7. 未来的规划

业务线梳理

2018 年下半年,团队从 6 个人增加到 21 个人,支持的业务类型也从单一的移动端方向,扩展了模型算法、Web 端、服务端产品线,业务线方向跨度很大。盘点下来,我们团队的业务主要分四个方向:

  • 移动广告 SDK
  • 移动广告 DSP 引擎
  • CRM 系统
  • 效能研发平台

三条不同的业务线,面临的情况各不相同,基本上涵盖了测试行业各种业务的通病。(效能平台本文先不做介绍)

SDK 业务的特点:

  • 并行版本多,对接了多个媒体端
  • 提测周期短,经常会有定制化需求紧急发版上线
  • 项目是模块化结构
  • 需要定制测试 Demo APP,本身无界面
  • 回归测试周期短,小改动频繁,整体回归测试代价高昂
  • 广告打点的特殊性,包括时序、计数、触发时机等,直接影响计费

移动广告 DSP 引擎

  • 收入线,风险高,压力大
  • 测试难度大,模型算法相关
  • 底层 C++,测试走读代码成本高
  • 关联上下游较多,排查困难
  • 广告类型多,数据量巨大

CRM 业务线

  • 业务逻辑极其复杂,十几个系统关联
  • 业务链路长
  • 财务、法务、合同类多测试多,风险高
  • 多个系统并行提测,相互耦合,测试逻辑和构造数据复杂
  • 流程管理比较乱,人员流动大
  • 测试效率化难

设定目标

托尔斯泰说:“幸福的家庭都是相似的,不幸的家庭各有各的不幸”。看了上面的问题,是不是多少能找到自己项目的影子?团队整合后,面临的问题形形色色,没办法挨个细说,我们团队对现有问题进行了拆解和讨论,并形成了三个大的目标来达成。

  • 目标 1: 整体规范项目流程规范,所有业务线自有 Jenkins 全部迁移到统一的流水线上,打造 CI、CT、CD 一体化,集中治理
  • 目标 2: 建立精准测试体系,完成 C++、Java、PHP 三个语言的代码覆盖率建设,辅助业务测试、自动化测试、流量回放等手段提升效果
  • 目标 3: 推进测试深入化,从广告投放平台深入到引擎的模型算法层面,对广告的模型和词典进行全方位监控及行为分析,降低人为失误造成的事故损失

团队推行 OKR 后有很多好处,具体参看团队之前写的文章:https://testerhome.com/articles/17888

围绕着上面提到的目标,我们拆解为四个季度要完成的 OKR,可以给大家看一下部分的 OKR 系统的截图:

补充一下:这个 okr 系统是奇效平台花一周时间做出来的,之前都是管理在 Excel 中

拆解任务

围绕着总体的三个目标,我们对项目流程进行了分解,分而治之,每个阶段要完成的事情都罗列了出来,大致如下:

从项目立项到发布上线,总共可以划分为五个阶段:

  • 需求阶段
  • 研发阶段(代码准入)
  • 测试阶段
  • 发布阶段
  • 监控阶段

我们推动开展测试的左移和右移工作,除了技术方案外,我们与研发团队一起协商了许多规范和检查机制,其中让我们受益颇多的有几个值得提一下(大厂同学可能觉得很诧异,不是本来就该这样么?):

  • 建立提测单机制,区分优先级,配置了提测看板,让一周的工作一目了然
  • 设定研发自测演示环节,研发会在测试环境进行主要功能演示,被测试同学围观后,提测质量逐渐高了起来
  • 统一 Jenkins 流水线后,通过 Docker 解决编译环境一致性问题,减少了提测后环境问题导致排查耗时
  • 配置文件规范。以前遇到很多次问题是因为研发本地自测的配置环境跟测试环境不一致造成的

在扫平了项目前期的人为障碍后,我们强化了测试能力建设,其中收效最大的主要是两件事:

  • 代码覆盖率检查
  • 模型算法监控

可能有人要问了,代码覆盖率检查已经是很多年前提到的概念了,并且在 2018 年已经很多公司已经建立了这样的测试手段,这里我想重点介绍一下我们是怎么用的。

代码覆盖率检查

提到代码覆盖率,社区里面大大小小可以找到几十篇类似的原理、搭建、使用等介绍的帖子,在这里我重点说一下我们团队的技术历程和思考。
前面提到的,我们团队三个业务线,用的语言分别是Java、C++、PHP。也就是说从一开始我们就不能集中技术力量去解决某个语言的覆盖率方案。好在现在互联网信息的便利,有 TesterHome 社区和 MTSC 大会这样的平台,让我们可以获取到很多优秀团队和公司的做法,这里简单罗列一下我们参考到的方案:

  • 2018 年 MTSC 大会:

    • 《双精准测试实践 - 陆金所》
    • 《汽车之家新车电商精准测试解决方案 - 闻小龙》
    • 《有赞测试 增量代码覆盖率工具》
    • 《基于 codediff 的差异代码覆盖率统计实现 - 转转》
  • 2019 年 MTSC 大会:

    • 《进化的覆盖率 -- 实时代码染色 - 蚂蚁金服》
    • 《恰如其分的自动化测试 - 淘宝》

我们的业务并没有比其他公司的业务独特到哪里去,只不过我们团队要同时解决三个语言的代码覆盖率设计,仅此特殊而已。

代码覆盖率的原则

在投入去做代码覆盖率的时候,我们明确了一个原则和几个期望:

  • 原则:代码覆盖率只是一种度量工具,辅助测试的手段,而非评判标准。

为什么这么说呢?我这里简单举几个例子:

function test(int a, int b){
    return a/b;
}

输入a=3b=6
// 行覆盖率:100%
// 漏测b=0

function test(int a, int b){
    if(a < 5 || b < 10) {
        return a/b
    } else {
        return 0 
    }
}

//输入1:a=3,b=6;
//覆盖率:50%
//输入2:a=10,b=11;
//覆盖率:50%
// 漏测b=0

这里不论是行覆盖率还是 branch 覆盖率为 100% 都说明不了任何问题,这个我们内部进行过认真的讨论,实际上我们在做代码覆盖率的时候,希望能把目光锁定到那些本次新增的代码、方法、类,但是覆盖率为 0 的情况,是什么情况导致我们覆盖为 0?冗余代码?预埋逻辑?覆盖不到?还是漏测了?

  • 期望:
    • 在项目快速迭代节奏下从容评估回归测试范围
    • 在海量回归 case 中快速提取测试 case
    • 在复杂业务场景中针对性设计用例
    • 对存量 case 进行梳理和删减
    • 对现有的自动手段进行效果跟踪和改进
    • 降低漏测场景的复现成本
    • 通过可视化度量的方式,促进测试质量的提升
    • 在项目流程中,形成质量卡点,强化质量意识

增量代码覆盖率

几种语言的代码覆盖率方案没办法写在一篇文章中,如果感兴趣的话在社区里都可以找到。这里简单介绍一下我们的方案设计:
PHP 代码覆盖率方案

php-code-caverage 并不支持增量报告的展示,如果需要展示的话也比较简单,只需要做如下事情:

  1. 加入增量 diff 数据(通过解析 git diff 数据得到);
  2. 在结构化覆盖率数据统计的时候增加增量覆盖率数据的相关字段;
  3. 覆盖率报告渲染程序中兼容新增的增量覆盖率数据字段;
  4. 修改对应的报告模板支持增量覆盖率信息;

PHP 增量代码覆盖率

C++ 代码覆盖率方案

C++ 代码覆盖率是我们另外一个组来实现的,其中的一些细节可以去搜一下 Qtest 测试之道里面的两篇文章《gcov C++ 代码覆盖率测试工具》原理篇和实践篇:
原理篇
实践篇

Java 代码覆盖率方案

Java 代码覆盖率的文章,社区里不胜枚举,这里就不再介绍了。

代码伪实时染色方案

在完成代码覆盖率统计并集成到 Jenkins 后,我们每周的周会都会追踪一下代码覆盖率对业务测试的帮助,一开始大家对覆盖率还是比较赞同,觉得可以辅助测试,假如发现覆盖率数据偏低会主动去检查是否是设计的用例没有执行到。后来有一些同学反馈说,他们通过覆盖率结果反推 case 非常的困难,流程太长。通过了解,我们发现业务测试在补充用例到时候需要做几件事:

  1. 清空之前到测试覆盖率数据
  2. 编译打包、部署环境
  3. 执行一个 “可能会” 提升覆盖率的测试场景
  4. 执行完了后,回收覆盖率数据到流水线
  5. 查看数据结果,是否有提升

在调试一条 case 的时候,整个反馈的链路太长,响应不及时,业务测试同学需要逐条的尝试 case 是否有效,耗费大量的时间。怎么解决这个问题?蚂蚁金服的议题启发了我们!
在跟蚂蚁的讲师沟通后,我们发现要做到他们那样的程度对我们这样的小团队来说不太可能,因为我们不具备这样的技术力量来修改编译器,而且我们还有多语言的需求。于是我们开始尝试了自己的野路子方式,伪实时代码染色系统

C++ 的染色系统(涉及到核心代码,不得不马赛克):

C++ 代码染色系统具备几个功能点:

  1. 环境随时切换和锁定

  2. 代码树实时更新,绘制完代码树结构后,再在树节点上追加 diff 信息和覆盖信息

  3. 增量代码返回结果只渲染代码树的相关增量文件,高亮显示已覆盖的行

  4. 支持精确生成单模块、单目录、单文件的覆盖率信息

  5. 支持远程操作覆盖率数据

当然系统功能远不止于此,截图太多会影响阅读体验,这里就不详细的介绍。目前我们在做 case 的录制回放,case 推荐等功能,目前效果还在观察,暂时不提。

Java 代码染色系统功能:
  1. 按测试设备和版本作为 index 来隔离数据

  2. 支持全量数据和增量数据切换

  3. 伪实时返回覆盖率数据,从测试完成到覆盖率数据返回,渲染代码树大约需要 0.5~2 秒,所以叫伪实时

  4. 功能测试完成后要手动刷新数据

团队代码覆盖率统计系统

这里做了覆盖率数据和流水线打通,关联到触发人员、BuildID 等信息。我们会关注几个点:

  • 重点关注增量覆盖率的变化趋势
  • 文件和代码行的剧烈波动会影响代码行覆盖率
  • 不追求每一次 build 都是百分百覆盖,只关注累计的测试覆盖率
  • leader 会追问为什么是这个覆盖率,组员能明确回答出来

总结
参考了业界的进展,我把精准测试的规划拆成了三个阶段:

当下我们刚刚把第一阶段的基础能力建设做完,第二阶段很多事情还在进行中,有些已经完成了但是在观察效果,有些还在建设中,很多大厂已经进入到第三个阶段智能化时代,小团队只能仰望和模仿。

模型算法监控体系

待补充

共收到 51 条回复 时间 点赞

写得贼好

赞,写的很不错,学习了。

很棒!支持一下

很不错

做得挺好了

很厉害!

赞, 可惜我们公司不具备做单测的条件和土壤,覆盖率分析也就无从谈起唉。

这肯定年终 PPT,然后 copy 下到论坛了

csl 回复

覆盖率不是非得基于单测

simple #12 · 2020年04月23日 Author
csl 回复

不必基于单测,我们是基于手工测试 + 自动化测试 + 流量回放来观察覆盖率数据的

simple #13 · 2020年04月23日 Author
回复

哈哈,还真不是,一部分是内部分享的内容,年终总结我们一般都是对这 OKR 来描述

覆盖率实时染色真的很棒啊
我们团队大部分是手机业务,之前在团队简单实践过,当时因为代码量过大,测试设备多,全量和增量的报告生产特别特别久,然后加上覆盖率数据是手动点击一个按钮生成和上传,系统测试的同学体验特别不好。后来听了去年进击的覆盖率,理想很丰满,但是实在超出我们的能力了,也就放弃了。
ps:请问你们的手机 app 上传覆盖率数据,是怎么实时推到后台去分析的呢?

去年我也做了覆盖率相关的,java 后端的。实时代码覆盖率,文件目录结构,纯文件夹没有文件的可以合并一下更清晰。
文件目录全量和增量可以切换,代码染色页面也可以全量和增量切换。

调用链,好棒。正在准备搞这个。

simple #17 · 2020年04月23日 Author
剪烛 回复

我们是 SDK 嘛,所以 Demo 是自己写的,弄了个悬浮窗,测完了点击一下悬浮窗上传数据,因为 case 执行完了有个时机判断,所以做成实时通信的方式反而不好。一开始我也特别担心生成覆盖率的时间很久,还跟蚂蚁的讲师沟通了一下,他们安卓的数据返回也有 3 秒以内的时延,我们的代码量没有那么大,所以时间更短一些,测试同学觉得可以接受。

simple #18 · 2020年04月23日 Author
陈子昂 回复

我们弄完了,还搞了可视化,感觉成本有点高。。。还在观察效果

simple 回复

0.0 所以你们 server 端是自己去读和分析代码路径,而不是用 jacoco 报告工具生成的?

simple #20 · 2020年04月23日 Author
剪烛 回复

不是,虽然我们对 jacoco 做了二次开发,但是整体上还是用的 jacoco 的数据,你看一下上面的设计图

咨询一下,jacoco 增量的时候匿名内部类如何计算的

simple #22 · 2020年04月23日 Author
花开 回复

知道您像表达的意思,通过 git diff 拿到的信息无法对匿名内部类做计数对吧?jacoco 在做全量的覆盖率统计的时候,是把匿名内部类作为独立的类来计算的,因为编译后的匿名内部类具有自己的独立 ID。但是在增量覆盖率筛选的时候,我们没有做增量的类覆盖率统计,主要统计增量的 diff 行变更,通过 diff 出来的行变更信息来标记结果报告中,辅助测试同学反推遗漏的测试场景。

优秀,向大佬学习👍

PS:第一张图最后 4 个人,1 蓝 1 红还有 2 个黑是啥个意思……

其实很多 “大公司方案” 是组织成本太高只好那样做的

能够这样清晰落地的不多,赞

simple #26 · 2020年04月24日 Author
sylan215 回复

观察的那么仔细👍 ,那两个是借的,兼职

研发自测演示环节,这个有点意思。传统大厂情况不清楚,但是游戏行业的一些大厂也没有这个过程,貌似可以实践一下

28楼 已删除

👍,其中问下,关于代码覆盖率,通过 SDK 接入到 APP,然后功能测试以及自动化测试,然后上传数据到后端进行展示。有个问题就是 jacoco 这个在后端集成,要怎么弄,之前做到这一步就结束了,另外就是每次得覆盖率是针对某一个版本的功能变更吧,因为这涉及到提测内容~。另外 jacoco 报告的查看,每次都要同样的版本才能编译解析查看,这个你是怎么解决效率问题~还是这个没有办法绕过

simple #30 · 2020年04月26日 Author
chenyouan 回复

我咨询了一下我们组的同学,他的答复如下(我无耻的照搬过来):

1jacoco如何在服务端集成
jacoco提供了多个jar包其中一个是jacococli.jar将它集成到服务端后进行方法(主要是report命令的相关方法)调用我们是基于这个jar包进行的二次开发修改了report命令相关的函数具体使用方式参考https://www.eclemma.org/jacoco/trunk/doc/cli.html
2jacoco如何保证在不同版本上的解析
首先明确一点jacoco解析是根据calssid进行确认的具体参考https://www.eclemma.org/jacoco/trunk/doc/classids.html这里。明确这一前提之下,不同时不同版本还是同一版本的不同build,均可以进行解析计算。
3jacoco解析的效率问题
jacoco在解析时的效率由两点确认(可通过jacococli.jar查看)一个是加载的exec文件一个是加载的class文件这是解析的核心也是解析命令中必要数据因此解析效率可以通过过滤exec或者class文件提升效率具体的根据业务特点和想要实现的需求进行判断考虑jacocoli的report入口源码位于org.jacoco.cli.internal.commands.Report类中的execute方法
simple 回复

感谢解答,我琢磨下~

向大佬学习🍻

陈恒捷 将本帖设为了精华贴 04月27日 08:25

2018 年 MTSC 大会
2019 年 MTSC 大会
这里面提到的文章,哪里可以找到呢

很赞的文章👍

挺好奇有多少人力投入到研发这一套东西里面?是否包括在上述 21 个人员当中呢。

simple #37 · 2020年05月06日 Author
Changjun Ji 回复

是的,都在这 21 个人里面,java 我们投入 1 个人,php 投入 1 人,C++ 投入 1.5 个人,这些同学只有 java 的是专门在做这个事情,另外他得负责 sdk 的 demo 开发,其他人都需要支持业务测试。(当然还包括我这个打杂人员)

大佬 在正常测试中代码肯定会发现些 bug 导致版本迭代,那覆盖率是不是版本迭代中把之前测试的覆盖率给继承下来,这个你们是怎么做的呀
还有你们的故障注入准备怎么做呀

两个字: 优秀~

CT 是指的组件测试么? component testing?

simple #41 · 2020年06月01日 Author
阿东 回复

是 Continuous Testing,我们把 API 自动化测试、性能压测、Diff 做到流水线里面,发布之前必须执行的测试手段,我简称 CT

同问,是怎么做到不同版本的 jacoco 覆盖率数据存储下来,然后伪实时在同一个页面显示。

貌似是骑虎的老哥,之前在奇酷软件做 华屹广告平台,投放引擎刚开始是 c++ 写的,后来全部转 golang 了。

发现了一个 bug Male and 男???

我推了一年多了,没有动起来;
上家公司是我老大推我做,我没做;
这家公司我推覆盖率,风水轮流转😹

大佬~问下你现在实时渲染展示的是后台的代码覆盖率还是前端的代码覆盖率?

simple #47 · 2020年07月28日 Author
zlp 回复

一个是移动端的(Android),一个是服务端的(C++)

写得好棒!
今年刚做好差异覆盖率。来年应该是代码调用链、函数跟用例映射。。。老兄,有没有可以白瞟的😍

图片 404 了,大佬能更新下吗😭

大佬,这个代码树是用什么工具实现的,自己解析目录下的文件名称么?

simple #52 · 2022年01月26日 Author
zlp 回复

用 elementUI 的组件,自己扩展的

simple #53 · 2022年01月26日 Author
jb 回复

我看了下没有 404 啊

大佬咨询下你们的 java 实时覆盖率方案,是不是没有用 jacoco 原生的 html 文件,而是项目的源码文件通过 git api 渲染,如果是增量的话通过 gitdiff 渲染出来源码文件,然后分析服务定时拉取后端的 exec 文件,不断的去分析 exec 文件拿到 xml 文件,然后 web 页面通过 websocket 或者 ajax 轮询不断调取解析结果,结果中会有行的是否覆盖信息行属于哪个类,然后进行实时染色。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册