You probably already read the Go Cover Story and are wondering why one of the following things is happening:

  • When using the vendor directory, tests fail
  • The -cover flag does not work with multiple packages
  • Code coverage is lower than expected

To make long things short, the command that resolves these issues is:

touch ./coverage.tmp && echo 'mode: atomic' > coverage.txt && go list ./... | grep -v /vendor | xargs -n1 -I{} sh -c 'go test -covermode=atomic -coverprofile=coverage.tmp -coverpkg $(go list ./... | grep -v /vendor | tr "\n" ",") {} && tail -n +2 coverage.tmp >> coverage.txt' && rm coverage.tmp

What's it doing?

  1. It generates a list of packages without the vendor directory
    go list ./... | grep -v /vendor
  2. It compiles a list of packages in the right format, that should be considered when collecting code coverage:
    $(go list ./... | grep -v /vendor | tr "\n" ",")
  3. It runs go test with flags covermode (atomic mode), coverprofile and coverpkg in the right order:
    xargs -n1 -I{} sh -c 'go test -covermode=atomic -coverprofile=coverage.tmp -coverpkg $(go list ./... | grep -v /vendor | tr "\n" ",") {} [...]a
  4. It concatenates the reports into one file, coverage.txt:
    tail -n +2 coverage.tmp >> coverage.txt

Now you will be able to get the real code coverage with commands like

go tool cover -html=coverage.txt
go tool cover -func=coverage.txt

and get an accurate code coverage with services such as Coveralls.io.