Table of Contents:
Overview
Building a binary for coverage profiling
Running a coverage-instrumented binary
Working with coverage data files
Frequently Asked Questions
Resources
Glossary
Beginning in Go 1.20, Go supports collection of coverage profiles from applications and from integration tests, larger and more complex tests for Go programs.
Go provides easy-to-use support for collecting coverage profiles at the level of package unit tests via the “go test -coverprofile=...
” command.
Starting with Go 1.20, users can now collect coverage profiles for larger integration tests: more heavy-weight, complex tests that perform multiple runs of a given application binary.
For unit tests, collecting a coverage profile and generating a report requires two steps: a go test -coverprofile=...
run, followed by an invocation of go tool cover {-func,-html}
to generate a report.
For integration tests, three steps are needed: a build step, a run step (which may involve multiple invocations of the binary from the build step), and finally a reporting step, as described below.
To build an application for collecting coverage profiles, pass the -cover
flag at the top level (package main
) build:
$ go build -cover -o myprogram.exe cmd/myprogram
$
The resulting binary can then be run using an environment variable setting to capture coverage profiles (see the next section on running).
How packages are selected for instrumentation
During a given “go build -cover
” invocation, the Go command will select packages in the main module for coverage profiling; other packages that feed into the build (dependencies listed in go.mod, or packages that are part of the Go standard library) will not be included by default.
For example, here is a toy program containing a main package, a local main-module package greetings
and a set of packages imported from outside the module, including (among others) rsc.io/quote
and fmt
(link to full program).
$ cat go.mod
module mydomain.com
go 1.20
require rsc.io/quote v1.5.2
require (
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
rsc.io/sampler v1.3.0 // indirect
)
$ cat myprogram.go
package main
import (
"fmt"
"mydomain.com/greetings"
"rsc.io/quote"
)
func main() {
fmt.Printf("I say %q and %qn", quote.Hello(), greetings.Goodbye())
}
$ cat greetings/greetings.go
package greetings
func Goodbye() string {
return "see ya"
}
$
If you build this program with the “-cover
” command line flag and run it, exactly two packages will be included in the profile: main
and mydomain.com/greetings
; the other dependent packages will be excluded.
Users who want to have more control over which packages are included for coverage can build with the “-coverpkg
” flag. Example:
$ go build -cover -o prog2.exe -coverpkg=io,mydomain.com,rsc.io/quote .
$
In the build above, the main package from mydomain.com
as well as the rsc.io/quote
and io
packages are selected for profiling; since mydomain.com/greetings
isn’t specifically listed, it will be excluded from the profile, even though it resides in the main module.
Binaries built with “-cover
” write out profile data files at the end of their execution to a directory specified via the environment variable GOCOVERDIR
. Example:
$ go build -cover -o myprogram.exe myprogram.go
$ mkdir somedata
$ GOCOVERDIR=somedata ./myprogram.exe
I say "Hello, world." and "see ya"
$ ls somedata
covcounters.c6de772f99010ef5925877a7b05db4cc.2424989.1670252383678349347
covmeta.c6de772f99010ef5925877a7b05db4cc
$
Note the two files that were written to the directory somedata
: these (binary) files contain the coverage results. See the following section on reporting for more on how to produce human-readable results from these data files.
If the GOCOVERDIR
environment variable is not set, a coverage-instrumented binary will still execute correctly, but will issue a warning.
Example:
$ ./myprogram.exe
warning: GOCOVERDIR not set, no coverage data emitted
I say "Hello, world." and