Testing
Use deterministic tests with clear diagnostics, then route helpers, coverage, fixtures, and concurrency-specific questions to narrower pages.
Canonical guidance
- prefer small, deterministic tests
- use table-driven tests when multiple cases share the same structure
- make failure messages identify the case and the violated expectation
- test behavior at meaningful boundaries, not private implementation trivia
- route helper, fixture, coverage, and concurrency-timing concerns to narrower testing pages
Use when
- unit tests
- subtests
- regression tests
Avoid
- brittle tests tied tightly to internals
- giant test functions with many unrelated scenarios
- hidden dependencies on wall-clock time or execution order
Preferred pattern
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := Parse(tc.in)
if got != tc.want {
t.Fatalf("Parse(%q) = %q, want %q", tc.in, got, tc.want)
}
})
}
Anti-pattern
- opaque assertions that fail without telling you which case broke
Explanation: This anti-pattern is tempting because terse assertions look clean, but weak diagnostics slow down debugging and make regressions harder to understand.
Why
- Go testing works best when cases are explicit, reproducible, and easy to extend
Related pages
Sources
- testing package - Go Team
- TableDrivenTests - Go Team