chikaku

且听风吟

永远是深夜有多好。
github
email

Go runtime code coverage collection

go1.20 introduced the ability to collect code coverage at runtime.

Coverage profiling support for integration tests

Below is a simple HTTP service as an example:

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 a -cover option at compile time.

$ go build -cover

Add an environment variable GOCOVERDIR at runtime to specify the coverage information output directory. After that, you just need to execute the binary normally. 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 a 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 output files
$ ls coverdata
covcounters.6fd39c6fc688fc732181f8d31bfc2c1f.7892.1677208447525456700
covmeta.6fd39c6fc688fc732181f8d31bfc2c1f

In the GOCOVERDIR, there will be covcounters and covmeta files. For the same binary file run multiple times, 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#

Obtain code test coverage directly through covdata, 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 executions together, where -i 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#

Using the cover tool, you can see the coverage situation of specific functions or code in more 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, output an HTML file
$ go tool cover -html=profile.txt
HTML output written to /tmp/cover3154511218/coverage.html

Open the output HTML file as follows:

coverage.html

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