chikaku

且听风吟

永远是深夜有多好。
github
email

Go 运行时代码覆盖率收集

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 下会存在 covcounterscovmeta 文件,对于同一份二进制文件多次运行只会输出一份 covmeta 文件

$ ls coverdata
covcounters.6fd39c6fc688fc732181f8d31bfc2c1f.12377.1677208539436884400
covcounters.6fd39c6fc688fc732181f8d31bfc2c1f.7892.1677208447525456700
covmeta.6fd39c6fc688fc732181f8d31bfc2c1f

接下来可以通过 go 工具链内新的 covdatacover 工具对输出的 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 文件如下:

coverage.html

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。