go test -cover 只给你一个百分比,背后是编译器在每个代码块里插入计数器。这篇看覆盖率文件里到底写了什么,三种模式有什么区别,插桩对速度的影响有多大,以及怎样给不是测试的程序收集覆盖率。
ok lab 0.112s coverage: 47.1% of statements
包里共 17 个语句(按覆盖率文件里各块的语句数相加:Classify 8 个、Unused 3 个、Hot 6 个),测试只调了 Classify,覆盖 8 个,47.1%。
-covermode=set:mode: set(每行:文件:起始行.列,结束行.列 语句数 计数)
f.go:4.2,4.11 1 1
f.go:5.3,6.1 1 1
f.go:7.2,7.12 1 1
f.go:8.3,9.1 1 1
f.go:10.2,10.28 1 1
f.go:11.3,11.15 1 1
f.go:12.4,13.1 1 1
f.go:15.2,15.22 1 1
f.go:19.2,22.1 3 0
f.go:25.2,26.25 2 0
f.go:27.3,27.15 1 0
f.go:28.4,29.1 1 0
f.go:30.4,31.1 1 0
f.go:33.2,33.10 1 0
-covermode=count:mode: count(每行:文件:起始行.列,结束行.列 语句数 计数)
f.go:4.2,4.11 1 6
f.go:5.3,6.1 1 1
f.go:7.2,7.12 1 5
f.go:8.3,9.1 1 1
f.go:10.2,10.28 1 4
f.go:11.3,11.15 1 5
f.go:12.4,13.1 1 1
f.go:15.2,15.22 1 3
f.go:19.2,22.1 3 0
f.go:25.2,26.25 2 0
f.go:27.3,27.15 1 0
f.go:28.4,29.1 1 0
f.go:30.4,31.1 1 0
f.go:33.2,33.10 1 0
-covermode=atomic:mode: atomic;各行的计数与 count 模式完全相同(单线程测试里没有区别)每一行是一个“块”:f.go:4.2,4.11 1 6 表示第 4 行第 2 列到第 4 行第 11 列的块,含 1 个语句,执行了 6 次。set 模式只记 0/1,count 记次数,atomic 的数值相同但多线程下正确。
f.go:3: Classify 100.0% f.go:18: Unused 0.0% f.go:24: Hot 0.0% total: (statements) 47.1%
go tool cover -func 把块汇总成每个函数的百分比,方便快速找到完全没被测到的函数(Unused、Hot 都是 0.0%)。
不插桩 304 ns/op;-covermode=set 710 ns/op(2.33 倍);count 1930 ns/op(6.34 倍);atomic 8038 ns/op(26.41 倍)
对一个只有几条语句的紧循环,set 模式让耗时变成 2.33 倍,count 6.34 倍,atomic 26.41 倍。真实函数里每条语句的工作量大得多,比例会小很多;但说明了为什么 -race 默认配 atomic、测基准时别带 -cover。
程序输出:质数或 1 负数;GOCOVERDIR 里生成了 2 个文件 go tool covdata percent:lab coverage: 35.3% of statements lab/cmd coverage: 100.0% of statements
go build -cover 编译出来的程序,运行时把数据写到 GOCOVERDIR 指定的目录;用 go tool covdata percent 汇总,实验里 lab 包 35.3%、lab/cmd 100.0%。可以用来收集集成测试、手工运行的覆盖率。
-covermode set,count,atomic Set the mode for coverage analysis for the package[s] being tested. The default is "set" unless -race is enabled, in which case it is "atomic". The values: set: bool: does this statement run? count: int: how many times does this statement run? atomic: int: count, but correct in multithreaded tests; significantly more expensive.
go help testflag 对三种模式的说明与实验一致:set 是“执行过吗”,count 是“几次”,atomic 是多线程正确的 count。