go-testinglisted
Install: claude install-skill AllThingsSmitty/agent-skills
Go tests should verify behavior, not implementation. Keep tests close to the code they test, name them clearly, and make failures self-explanatory without a debugger.
## Table-Driven Tests
Table-driven tests are the idiomatic Go pattern for testing a function across multiple inputs. Use a slice of structs with `name`, input, and expected fields. Always use `t.Run` for each case — this gives each case an identity in the output.
```go
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
}{
{"positive numbers", 2, 3, 5},
{"negative numbers", -1, -2, -3},
{"zeros", 0, 0, 0},
{"mixed signs", -4, 6, 2},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := Add(tc.a, tc.b)
if got != tc.expected {
t.Errorf("Add(%d, %d) = %d, want %d", tc.a, tc.b, got, tc.expected)
}
})
}
}
```
Run a single case: `go test -run TestAdd/positive_numbers`.
## Subtests and t.Run
`t.Run` creates a named subtest. Each subtest is independently reported, filterable, and can be run in parallel.
```go
func TestUserCreate(t *testing.T) {
// Shared setup runs once here
t.Run("valid input creates user", func(t *testing.T) {
t.Parallel() // safe to run alongside other parallel subtests
// ...
})
t.Run("duplicate email returns error", func(t *testing.T) {
t.Parallel()