Go table-driven tests
Table-driven tests are the idiomatic Go pattern for exercising one function across many input/output pairs without duplicating boilerplate. They keep coverage dense, diffs small, and failure messages precise. This recipe walks through the canonical structure, subtests, and parallelism.
1.Define the table
Declare an anonymous struct slice with one field per input plus the expected output. Give every case a descriptive name so failures point at the case, not the index.
tests := []struct {
name string
in string
want int
}{
{"empty", "", 0},
{"single", "a", 1},
{"ascii", "hello", 5},
{"unicode", "café", 4},
}2.Run as subtests
Wrap each iteration in t.Run so the Go test runner reports each case independently. You can target a single case withgo test -run TestLen/unicode.
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := RuneCount(tc.in)
if got != tc.want {
t.Errorf("RuneCount(%q) = %d, want %d", tc.in, got, tc.want)
}
})
}3.Parallelize safely
Call t.Parallel() inside the subtest to run cases concurrently. On Go versions before 1.22, capture the loop variable into a local to avoid the classic shared-iterator bug.
for _, tc := range tests {
tc := tc // pin for Go < 1.22
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
if got := RuneCount(tc.in); got != tc.want {
t.Errorf("got %d want %d", got, tc.want)
}
})
}