go1.20
引入了在运行时收集代码覆盖率的的功能
Coverage profiling support for integration tests
下面用一个简单的 HTTP 服务作为示例:
func main() {
var firstVisit atomic.Bool
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if firstVisit.CompareAndSwap(false, true) {
w.Write([]byte("Hello first visiter"))
} else {
w.Write([]byte("Hello"))
}
})
done := make(chan struct{})
http.HandleFunc("/exit", func(w http.ResponseWriter, r *http.Request) {
close(done)
})
go func() {
if err := http.ListenAndServe(":8000", nil); err != nil {
panic(err)
}
}()
<-done
}
在编译时添加一个 -cover
选项
$ go build -cover
在运行时添加一个 GOCOVERDIR
的环境变量指定 coverage 信息输出目录,后续只需要正常执行二进制即可。进程正常结束后后在指定的 GOCOVERDIR
目录下可以看到 coverage 相关的文件。如果程序非正常结束比如由于 panic 或者被 os.Exit 终止输出的文件可能是不完整的。
# 启动 HTTP 服务器
$ GOCOVERDIR=./coverdata ./demo
# 测试接口
$ http 127.0.0.1:8000/
$ http 127.0.0.1:8000/exit
# 查看输出文件
$ ls coverdata
covcounters.6fd39c6fc688fc732181f8d31bfc2c1f.7892.1677208447525456700
covmeta.6fd39c6fc688fc732181f8d31bfc2c1f
GOCOVERDIR 下会存在 covcounters
和 covmeta
文件,对于同一份二进制文件多次运行只会输出一份 covmeta 文件
$ ls coverdata
covcounters.6fd39c6fc688fc732181f8d31bfc2c1f.12377.1677208539436884400
covcounters.6fd39c6fc688fc732181f8d31bfc2c1f.7892.1677208447525456700
covmeta.6fd39c6fc688fc732181f8d31bfc2c1f
接下来可以通过 go 工具链内新的 covdata
和 cover
工具对输出的 coverage 二进制文件做一些处理
$ go tool covdata <mode> -i=<dir1,dir2,...> ...flags...
$ go tool cover {-func,-html}
示例#
直接输出覆盖率#
通过 covdata
直接获得代码测试覆盖率,并输出一个与 go test -cover
相同的 coverprofile
$ go tool covdata percent -i=./coverdata -o profile.txt
golab/demo coverage: 83.3% of statements
合并多次测试#
通过 covdata
将多次执行输出的 covcounters 文件合并到一起,其中 -i
可以指定多个目录
$ go tool covdata merge -i=./coverdata -o=merged
$ ls merged
covcounters.6fd39c6fc688fc732181f8d31bfc2c1f.0.1677208798216472900
covmeta.6fd39c6fc688fc732181f8d31bfc2c1f
按函数 / 行查看覆盖率#
通过 cover
工具可以比较详细的看到具体函数或者代码的覆盖率情况
# 按函数看
$ go tool cover -func=profile.txt
golab/demo/main.go:8: main 83.3%
total: (statements) 83.3%
# 按行看, 输出一个 html 文件
$ go tool cover -html=profile.txt
HTML output written to /tmp/cover3154511218/coverage.html
打开输出的 html 文件如下: