go test
that fails on untested lines and shows them
- 🎉 Instant and actionable feedback on 💚 test run
- 🚀 Fast PRs: avoid comments and CI failures
- 💰 No 3rd-party payment / integration / security-leaks
- Highlight untested code sections with inline
// untested section
comment - Onboard untested code (top of the file
// untested sections: 5
comment) - Ignore untested files (top of the file
// untested sections: ignore
comment) - Run
ginko
withgo-testcov ginko ./...
go get github.com/grosser/go-testcov
go-testcov . # same arguments as `go test` uses, so for example `go-testcov ./...` for everything
...
test output
...
pkg.go new untested sections introduced (2 current vs 0 configured)
pkg.go:20.14,21.11
pkg.go:54.5,56.5
- Docs for coverage in go
- Runtime overhead for coverage is about 3%
- Use
-covermode atomic
when testing parallel algorithms - To keep the
coverage.out
file run with-cover
go-testcov version
to see current version
.PHONY: test
test: go-testcov ## Unit test
$(GOTESTCOV) ./... -covermode atomic
LOCALBIN ?= $(shell pwd)/bin
$(LOCALBIN):
mkdir -p $(LOCALBIN)
GOTESTCOV ?= $(LOCALBIN)/go-testcov
GOTESTCOV_VERSION ?= v1.10.0
.PHONY: go-testcov
go-testcov: $(LOCALBIN) # Download go-testcov (replace existing if incorrect version)
@(test -f $(GOTESTCOV) && $(GOTESTCOV) version | grep "$(GOTESTCOV_VERSION)" >/dev/null) || \
(rm -f $(GOTESTCOV) && echo "Installing $(GOTESTCOV) $(GOTESTCOV_VERSION)" && \
GOBIN=$(LOCALBIN) go install github.com/grosser/go-testcov@$(GOTESTCOV_VERSION))
graph TD;
GoTestCov(go-testcov .)
GoTest(go test . -cover --coverprofile coverage.out)
Coverage(coverage.out)
GoTestCov--runs-->GoTest;
GoTest--produces-->Coverage;
GoTestCov--parses-->Coverage;
coverage.out
shows the coverage of each file "section".
A "section" is a chunk of uninterrupted code, for example:
func main() {
if foo(1) {
fmt.Print("Hi")
}
fmt.Print("Ho")
}
has 3 sections:
github.com/foo/bar/main.go:1.13,2.13 1 1
github.com/foo/bar/main.go:2.13,3.4 1 1
github.com/foo/bar/main.go:5.3,5.18 1 1
1.13,2.13
: after openingmain() {
until afterif foo(1) {
2.13,3.4
: afterif foo(1) {
until afterif
closing}
5.3,5.18
:fmt.Print("Ho")
- the
else
case (aka "what if foo(1) returns false") has no coverage information - when not using modules the path is
/full/path/to/main.go
Run go-testcov
on itself:
make
- all tests are in
test/
so the main library does not force installation of gomega + ginkgo - the files from the root folder are symlinked there to make everything load
- easiest to work from that folder directly
- make new version commit that changes version in readme "Makefile setup" + main.go
- push and tag the commit
Michael Grosser
michael@grosser.it
License: MIT