How does test coverage work in Go? Explain covermode, -coverpkg, and coverage for integration tests.
Question 386MediumGo 1.22 to 1.25
The toolchain rewrites source to increment counters per basic block.
go test -coverprofile=cover.out ./...
go tool cover -func=cover.out # per-function percentages
go tool cover -html=cover.out # annotated source
go test -covermode=atomic -coverpkg=./... ./...
-covermode:set(was it run?),count(how many times),atomic(count, safe under concurrency — the default when-raceis on).-coverpkg=./...: by default coverage counts only the package under test; this counts code in other packages exercised by the tests too (e.g. handlers tested via an e2e package).
Integration coverage (Go 1.20+): build a real binary with coverage instrumentation, run it, and collect data:
go build -cover -o app ./cmd/app
GOCOVERDIR=./covdata ./app --run-scenario # writes counter files on exit
go tool covdata percent -i=./covdata
go tool covdata textfmt -i=./covdata -o=cover.out
Interviewer is looking for: coverage is a tool for finding untested code, not a quality target — 100% line coverage says nothing about asserting the right behavior or edge cases. Error branches and concurrency paths are what usually lack coverage. Mutation testing or fuzzing find what coverage misses.
More on Performance, Profiling & Testing
- Q384How do you mock dependencies in Go without a mocking framework? Where should the interface live?
- Q385How do you test HTTP handlers and HTTP clients with net/http/httptest?
- Q387What is Profile-Guided Optimization (PGO) in Go, and how do you use it?
- Q388How does inlining work in the Go compiler, how do you inspect it, and what prevents a function from being inlined?
- Q389Explain escape analysis. Which of these allocate on the heap?
- Q390What is bounds check elimination (BCE), how do you see it, and how can you help the compiler?