文章
测试覆盖度
定义:Test coverage(测试覆盖度)用于衡量一个包中的代码被测试用例覆盖的程度。
如果运行所有的测试用例能够触发包中80%的代码运行,我们就认为测试覆盖度为80%。
通常情况下,要计算测试覆盖率,需要对执行文件进行二进制拦截,比如gcov工具:通过在每个逻辑分支之后添加一个断点,来标记这个分支是否被执行到。这种基于二进制拦截的方法移植性不够好,需要针对不同CPU架构来实现。
go test -cover
通过对源代码进行重写,在分支中添加对应的监控语句来实现。例子:
package size
func Size(a int) string {
switch {
case a < 0:
return "negative"
case a == 0:
return "zero"
case a < 10:
return "small"
case a < 100:
return "big"
case a < 1000:
return "huge"
}
return "enormous"
}
重写后:
func Size(a int) string {
GoCover.Count[0] = 1
switch {
case a < 0:
GoCover.Count[2] = 1
return "negative"
case a == 0:
GoCover.Count[3] = 1
return "zero"
case a < 10:
GoCover.Count[4] = 1
return "small"
case a < 100:
GoCover.Count[5] = 1
return "big"
case a < 1000:
GoCover.Count[6] = 1
return "huge"
}
GoCover.Count[1] = 1
return "enormous"
}
GoCover.Count[]
是一个计数器,用于统计程序中每个分支对应是否执行过。
go test -cover
只输出百分比结果,可以通过go test -coverprofile=cover.out
来查看详细的情况:
这个文件是不容易解读的,通过go tool cover -html=cover.out
打开网页查看:
热力图
覆盖度工具不仅可以记录分支是否被执行,还可以记录分支被执行了多少次。
go test -covermode=set|count|atomic
:
-covermode
:
- set: 默认模式,统计是否执行
- count: 计数
- atomic: count的并发安全版本,仅当需要精确统计时使用
统计fmt
包:
$ go test -covermode=count -coverprofile=count.out fmt
ok fmt 1.320s coverage: 95.1% of statements
将鼠标悬浮在代码块上可以看到具体执行的数据。
通过go tool cover -func=count.out
查看每个函数的覆盖度:
$ go tool cover -func=count.out
fmt/format.go: init 100.0%
fmt/format.go: clearflags 100.0%
fmt/format.go: init 100.0%
fmt/format.go: computePadding 84.6%
fmt/format.go: writePadding 100.0%
fmt/format.go: pad 100.0%
...
fmt/scan.go: advance 96.2%
fmt/scan.go: doScanf 96.8%
total: (statements) 91.7%
也许从这些测试中可以得到关于性能优化的提示。