"聊点干货"html
截止到Go1.15.2之前,关于覆盖率技术底层实现,如下知识点您应该知道:git
go语言采用的是插桩源码的形式,而不是待二进制执行时再去设置breakpoints。这就致使了当前go的测试覆盖率收集技术,必定是侵入式的,会修改目标程序源码。曾经有同窗会问,插过桩的二进制能不能放到线上,因此建议最好不要。github
到底什么是"插桩"?这个问题很关键。你们能够任意找一个go文件,试试命令go tool cover -mode=count -var=CoverageVariableName xxxx.go
,看看输出的文件是什么?后端
笔者以这个文件为例https://github.com/qiniu/goc/blob/master/goc.go
, 获得如下结果:数组
package main import "github.com/qiniu/goc/cmd" func main() {CoverageVariableName.Count[0]++; cmd.Execute() } var CoverageVariableName = struct { Count [1]uint32 Pos [3 * 1]uint32 NumStmt [1]uint16 } { Pos: [3 * 1]uint32{ 21, 23, 0x2000d, // [0] }, NumStmt: [1]uint16{ 1, // 0 }, }
能够看到,执行完以后,源码里多了个CoverageVariableName
变量,其有三个比较关键的属性:架构
* `Count` uint32数组,数组中每一个元素表明相应基本块(basic block)被执行到的次数 * `Pos` 表明的各个基本块在源码文件中的位置,三个为一组。好比这里的`21`表明该基本块的起始行数,`23`表明结束行数,`0x2000d`比较有趣,其前16位表明结束列数,后16位表明起始列数。经过行和列能惟一肯定一个点,而经过起始点和结束点,就能精确表达某基本块在源码文件中的物理范围 * `NumStmt` 表明相应基本块范围内有多少语句(statement) `CoverageVariableName`变量会在每一个执行逻辑单元设置个计数器,好比`CoverageVariableName.Count[0]++`, 而这就是所谓插桩了。经过这个计数器能很方便的计算出这块代码是否被执行到,以及执行了多少次。相信你们必定见过表示go覆盖率结果的coverprofile数据,相似下面: `github.com/qiniu/goc/goc.go:21.13,23.2 1 1` 这里的内容就是经过相似上面的变量`CoverageVariableName`获得。其基本语义为 "**文件:起始行.起始列,结束行.结束列 该基本块中的语句数量 该基本块被执行到的次数**"
依托于go语言官方强大的工具链,你们能够很是方便的作单测覆盖率收集与统计。可是集测/E2E就不是那么方便了。不过好在咱们如今有了https://github.com/qiniu/goc。模块化
关于单测这块,深刻go源码,咱们会发现go test -cover
命令会自动生成一个_testmain.go
文件。这个文件会Import各个插过桩的包,这样就能够直接读取插桩变量,从而计算测试覆盖率。实际上goc
也是相似的原理(PS: 关于为什么不直接用go test -c -cover
方案,能够参考这里https://mp.weixin.qq.com/s/DzXEXwepaouSuD2dPVloOg)。工具
不过集测时,被测对象一般是完整产品,涉及到多个long running的后端服务。因此goc在设计上会自动化会给每一个服务注入HTTP API,同时经过服务注册中心goc server
来管理全部被测服务。如此的话,就能够在运行时,经过命令goc profile
实时获取整个集群的覆盖率结果,当真很是方便。测试
总体架构参见:
ui
技术须要为企业价值服务,否则就是在耍流氓。能够看到,目前玩覆盖率的,主要有如下几个方向:
度量 - 深度度量,各类包,文件,方法度量,都属于该体系。其背后的价值在于反馈与发现。反馈测试水平如何,发现不足或风险并予以提升。好比常见的做为流水线准入标准,发布门禁等等。度量是基础,但不能止步于数据。覆盖率的终极目标,是提升测试覆盖率,尤为是自动化场景的覆盖率,并一以贯之。因此基于此,业界咱们看到,作的比较有价值的落地形态是增量覆盖率的度量。goc diff 结合Prow平台也落地了相似的能力,若是您内部也使用Kubernetes,不妨尝试一下。固然同类型的比较知名的商业化服务,也有CodeCov/Coveralls等,不过目前她们多数是局限在单测领域。
精准测试方向 - 这是个很大的方向,其背后的价值逻辑比较清晰,就是创建业务到代码的双向反馈,用于提高测试行为的精准高效。但这里其实含有悖论,懂代码的同窗,大几率不须要无脑反馈;不能深刻到代码的同窗,你给代码级别的反馈,也效果不大。因此这里落地姿式很重要。目前业界没还看到有比较好的实践例子,大部分都是解决特定场景下的问题,有必定的局限。
而相较于落地方向,做为广大研发同窗,下面这些最佳实践可能对您更有价值:
谷歌有篇博客(参考资料)提到,其经验代表,重视代码覆盖率的团队一般会更加容易培养卓越工程师文化,由于这些团队在设计产品之初就会考虑可测性问题,以便能更轻松的实现测试目标。而这些措施反过来会促使工程师编写更高质量的代码,更注重模块化。
最后,欢迎点击左下角详情按钮,加入七牛云Goc交流群,咱们一块儿聊聊goc,聊聊研发效能那些事。
参考资料