Built-in testing: go test, table tests, benchmarks, fuzzing.
Benchmarks and Fuzz Tests
Beyond regular tests, Go's testing package ships two more tools:
- Benchmarks — measure performance.
- Fuzz tests — generate random inputs and look for crashes / failures.
Both live in _test.go files. Names matter: Benchmark… and Fuzz….
Benchmarks
A benchmark function receives *testing.B. The runner calls it with increasing
values of b.N until it gets a stable timing.
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
Add(2, 3)
}
}
Run benchmarks with:
go test -bench=. # run benchmarks in current package
go test -bench=. -benchmem # also report allocations
Sample output:
BenchmarkAdd-8 1000000000 0.305 ns/op 0 B/op 0 allocs/op
0.305 ns/op— average wall-clock per iteration.B/opandallocs/op— bytes and allocations per iteration (needs-benchmem).
Fuzz tests (Go 1.18+)
A fuzz test takes a "seed corpus" and generates random inputs around it, looking for inputs that crash or break invariants.
func FuzzReverse(f *testing.F) {
f.Add("hello")
f.Fuzz(func(t *testing.T, s string) {
r := Reverse(s)
if Reverse(r) != s {
t.Errorf("not stable: %q", s)
}
})
}
go test -fuzz=FuzzReverse # run forever until it finds a failure or you Ctrl+C
When fuzzing finds a failing input, it writes a regression case into
testdata/fuzz/... so the failure is reproducible in regular runs.
Comparing benchmarks: benchstat
To know whether a change actually improved things, save the output and use
benchstat:
go test -bench=. -count=10 > old.txt
# ... make your change ...
go test -bench=. -count=10 > new.txt
benchstat old.txt new.txt
This runs each benchmark 10 times and reports the change with statistical significance — so you don't chase noise.