skip to content

Automated Testing

Go ships its test framework in the standard library: go test and the testing package, no runner to choose, no assertion DSL. Tables, doubles, benchmarks, fuzz targets and flake control all live here.

part ofGo (Golang)overview, primer and where to startread it →
on this pageshow

explore

questions

102 · 5 sections

Go's testing package has no assertEqual - how do you compare a value against an expected one in a test?

level: juniorimportance: must knowfreq 70%
basics
~20 s

You compare with ordinary Go code: == for comparable types, reflect.DeepEqual or slices.Equal for composites. On a mismatch call t.Errorf and print both values, conventionally the value you got first, then the value you wanted.

open as a page

What does declaring `package foo_test` in a _test.go file change versus declaring `package foo`?

level: juniorimportance: must knowfreq 58%
basics
~20 s

A _test.go file declaring package foo compiles into the package itself and can use its unexported identifiers. One declaring package foo_test compiles as a separate package that must import foo and sees only its exported API.

open as a page

Why do Go tests keep fixture files in a directory named testdata, and how does the go command treat it?

level: juniorimportance: must knowfreq 50%
basics
~20 s

The go command ignores directories named testdata when matching package patterns, so nothing inside is compiled or vetted. A test binary runs with its own package directory as the working directory, so a relative path like testdata/user.go.golden always resolves.

open as a page

In a Go test, what does t.TempDir() return and who deletes that directory?

level: juniorimportance: must knowfreq 58%
basics
~20 s

t.TempDir() returns the path of a fresh, empty directory created for that test. The testing package removes it automatically once the test and all of its subtests have completed, so the test never writes its own removal code.

open as a page

What does calling t.Parallel() in a Go test do, and when does that test's body actually run?

level: juniorimportance: must knowfreq 60%
basics
~20 s

t.Parallel() marks a test as safe to run alongside other tests that also call it. The call pauses the test immediately; it resumes only after its parent test function has returned, and then runs concurrently with its parallel siblings.

open as a page

How do you make a Go type that calls time.Now() testable, and why is a now func() time.Time field the usual seam?

level: juniorimportance: must knowfreq 58%
basics
~20 s

Store the clock as a func() time.Time field that defaults to time.Now, and read the time through it. A test assigns a closure returning a fixed time.Date value, so results no longer depend on when the test runs.

open as a page

How do you exercise an http.Handler directly in a Go test without binding a port?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Build the request with httptest.NewRequest and pass it, together with an httptest.NewRecorder, straight to the handler's ServeHTTP. The recorder captures status, headers and body in memory, so no port is bound and nothing is served.

open as a page

How do you make a Go service that reads users from a database unit-testable without one?

level: juniorimportance: must knowfreq 68%
basics
~20 s

Declare a small interface in the package that uses the dependency, naming only the one or two methods that code actually calls. Take it as a constructor parameter. In a _test.go file, pass a hand-written struct that implements those methods.

open as a page

Go's `testing` package has no assertion API — how do you check a mock's recorded calls, and when is `t.Fatalf` wrong?

level: middleimportance: must knowfreq 62%
basics
~20 s

You compare with a plain if and report with t.Errorf, using the got/want convention: if got != want { t.Errorf("Update calls = %d, want %d", got, want) }. t.Errorf records the failure and keeps going; t.Fatalf stops the test and is valid only on the goroutine running the test function.

open as a page

What does a `//go:generate` line above an interface do, and when does that command actually run?

level: juniorimportance: should knowfreq 48%
basics
~20 s

It is an ordinary comment that the compiler ignores. Only an explicit go generate run scans source files for lines starting with //go:generate and executes the rest as a command in that package's directory. go build and go test never trigger it.

open as a page

In `go test` output, what does the `(cached)` marker mean, and how do you force a real run?

level: juniorimportance: must knowfreq 58%
basics
~10 s

The (cached) marker means go test found a stored successful result for that package and reprinted its output instead of running the test binary. Only passing runs are stored; add -count=1 to force execution.

open as a page

How do you produce a `go test` coverage profile and view which lines were never executed?

level: juniorimportance: must knowfreq 62%
basics
~20 s

Run go test -coverprofile=cover.out ./... to write a coverage profile file, then go tool cover -func=cover.out for per-function percentages, or go tool cover -html=cover.out to open a page where every uncovered source line is highlighted.

open as a page

What does go test -race do, and what happens to the run when it detects a race?

level: juniorimportance: must knowfreq 70%
basics
~20 s

go test -race compiles the tests with the race detector, which watches memory accesses as they run. A conflict prints a WARNING: DATA RACE report naming both accesses with their goroutine stacks, fails that test, and makes go test exit non-zero.

open as a page

What is func TestMain(m *testing.M), and when does go test call it instead of running tests?

level: juniorimportance: must knowfreq 55%
basics
~20 s

TestMain is an optional function a test package may declare. The test binary then calls it instead of running the tests directly, and the tests run only when it calls m.Run. It is the hook for package-wide setup and teardown.

open as a page

How do you put a Go integration test file behind a build tag so it runs only on demand?

level: middleimportance: must knowfreq 55%
basics
~20 s

Put //go:build integration on the first line of the _test.go file, followed by a blank line before the package clause. The file is then excluded from every ordinary go test run and compiled back in only by go test -tags=integration.

open as a page

Where does `go test -fuzz` save an input that makes a fuzz target fail, and what replays it later?

level: juniorimportance: must knowfreq 42%
basics
~20 s

The fuzzing engine writes the failing input into a new file under testdata/fuzz/<FuzzName>/ in the package's own directory. That file becomes a seed corpus entry, so every later plain go test run replays it, with no -fuzz flag needed.

open as a page

What does a Go fuzz target `func FuzzParseQuery(f *testing.F)` do, and what are `f.Add` and `f.Fuzz` for?

level: juniorimportance: must knowfreq 48%
basics
~20 s

A Go fuzz target is a FuzzXxx function in a _test.go file that takes *testing.F. f.Add registers seed inputs; f.Fuzz takes the callback the engine runs, first on those seeds and then on mutated variations of them.

open as a page

In a Go benchmark func BenchmarkX(b *testing.B), what is b.N and who sets its value?

level: juniorimportance: must knowfreq 70%
basics
~20 s

b.N is the iteration count the testing package hands a benchmark; you never set it. go test calls the whole function repeatedly with a growing b.N until the run reaches -benchtime, then reports elapsed time divided by b.N.

open as a page

A Go benchmark that hashes a 1 MiB buffer reports 0.3 ns/op — what most likely happened?

level: juniorimportance: should knowfreq 42%
basics
~20 s

The compiler deleted the work. A function with no side effects whose result is never used becomes dead code once it is inlined, so the loop measures only its own counter. Keep the result alive by storing it in a package-level variable.

open as a page

How does the seed corpus under `testdata/fuzz` differ from the fuzzing corpus Go keeps in the build cache?

level: middleimportance: should knowfreq 34%
basics
~20 s

testdata/fuzz is checked-in source: it travels with the repository and runs on every plain go test. The generated corpus lives in the build cache directory, is machine-local, is only used while fuzzing, and go clean -fuzzcache deletes it.

open as a page

Why does a test asserting runtime.NumGoroutine() is unchanged fail intermittently?

level: middleimportance: must knowfreq 55%
basics
~20 s

The number is process-wide and momentary: a goroutine told to stop may not have run its last statement, other packages start background goroutines lazily, and parallel tests share the count. Poll to a deadline and compare stacks.

open as a page

A worker-pool test sleeps 50ms before asserting and goes red in CI weekly — how do you prove the sleep is the cause?

level: seniorimportance: must knowfreq 62%
basics
~20 s

Make it fail on demand rather than reasoning about it: narrow with -run, repeat with -count, build with -race, and squeeze the parallelism the way CI does. Then vary the sleep constant — if the failure rate tracks it, the sleep is the synchronisation.

open as a page

Why does re-running `go test` after a flaky failure print `(cached)`, and how do you force a real re-run?

level: juniorimportance: should knowfreq 55%
basics
~20 s

Go's test cache stores the result of a run that succeeded and replays it when nothing relevant changed, printing (cached) without executing anything. Add -count=1 to force a real run, or discard the stored results with go clean -testcache.

open as a page

How can a Go test detect that the code it exercised left a goroutine still running?

level: juniorimportance: should knowfreq 45%
basics
~20 s

Sample runtime.NumGoroutine() before the exercised code and again after it should have shut down; a higher number means something never exited. Dumping the runtime/pprof goroutine profile instead of counting also shows the leftover stacks, so you learn where.

open as a page

What does testing/synctest's Test function give a Go test that real time.Sleep calls cannot?

level: juniorimportance: should knowfreq 26%
basics
~20 s

synctest.Test runs a test inside a bubble with a fake clock, so time.Sleep, timers and tickers jump forward instantly instead of really waiting. A five-minute expiry can be tested in microseconds, with no slow-machine flakes.

open as a page