go1.20
引入了在運行時收集代碼覆蓋率的功能
下面用一個簡單的 HTTP 服務作為示例:
func main() {
var firstVisit atomic.Bool
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if firstVisit.CompareAndSwap(false, true) {
w.Write([]byte("你好,第一次訪問者"))
} else {
w.Write([]byte("你好"))
}
})
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
的環境變量指定覆蓋信息輸出目錄,後續只需要正常執行二進制即可。進程正常結束後在指定的 GOCOVERDIR
目錄下可以看到覆蓋相關的文件。如果程序非正常結束比如由於 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
工具對輸出的覆蓋二進制文件做一些處理
$ 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 覆蓋率: 83.3% 的語句
合併多次測試#
通過 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 輸出寫入到 /tmp/cover3154511218/coverage.html
打開輸出的 html 文件如下: