chikaku

且听风吟

永远是深夜有多好。
github
email

Go runtime code coverage collection

go1.20 introduced the functionality of collecting code coverage at runtime.

Coverage profiling support for integration tests

Here is an example using a simple HTTP server:

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 visitor"))
        } 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
}

Add the -cover option during compilation:

$ go build -cover

Add the GOCOVERDIR environment variable at runtime to specify the output directory for coverage information. After that, you can simply execute the binary as usual. After the process ends normally, you can see the coverage-related files in the specified GOCOVERDIR directory. If the program ends abnormally, such as due to panic or being terminated by os.Exit, the output files may be incomplete.

# Start the HTTP server
$ GOCOVERDIR=./coverdata ./demo
# Test the interface
$ http 127.0.0.1:8000/
$ http 127.0.0.1:8000/exit
# View the output files
$ ls coverdata
covcounters.6fd39c6fc688fc732181f8d31bfc2c1f.7892.1677208447525456700
covmeta.6fd39c6fc688fc732181f8d31bfc2c1f

Under GOCOVERDIR, there will be covcounters and covmeta files. For multiple runs of the same binary, only one covmeta file will be output.

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

Next, you can use the new covdata and cover tools in the Go toolchain to process the output coverage binary files.

$ go tool covdata <mode> -i=<dir1,dir2,...> ...flags...
$ go tool cover {-func,-html} 

Example#

Directly output coverage#

Use covdata to directly obtain code test coverage and output a coverprofile that is the same as go test -cover.

$ go tool covdata percent -i=./coverdata -o profile.txt
    golab/demo      coverage: 83.3% of statements

Merge multiple tests#

Use covdata to merge the covcounters files output from multiple runs. The -i option can specify multiple directories.

$ go tool covdata merge -i=./coverdata -o=merged
$ ls merged
covcounters.6fd39c6fc688fc732181f8d31bfc2c1f.0.1677208798216472900
covmeta.6fd39c6fc688fc732181f8d31bfc2c1f

View coverage by function/line#

Use the cover tool to see the coverage of specific functions or code in detail.

# View by function
$ go tool cover -func=profile.txt
golab/demo/main.go:8:   main            83.3%
total:                  (statements)    83.3%
# View by line and output an HTML file
$ go tool cover -html=profile.txt
HTML output written to /tmp/cover3154511218/coverage.html

Open the generated HTML file:

coverage.html

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.