Write a table-driven test by defining a slice of structs containing inputs and expected outputs, then loop over that slice in your test function to verify behavior for each case.
func TestMyFunction(t *testing.T) {
tests := []struct {
name string
input int
expected int
}{
{"positive", 1, 2},
{"negative", -1, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := MyFunction(tt.input); got != tt.expected {
t.Errorf("MyFunction(%v) = %v, want %v", tt.input, got, tt.expected)
}
})
}
}
This pattern keeps test logic DRY, makes adding new cases trivial, and provides clear failure messages via t.Run subtests.