Наиболее идиоматичен table-driven tests: массив (слайс) структур с входными данными и ожидаемым результатом, один цикл с t.Run(subtestName, func(t *testing.T) { ... }). Легко добавлять новые кейсы, все сценарии видны в одном месте.
func TestAdd(t *testing.T) {
tests := []struct {
a, b, want int
}{
{1, 2, 3},
{0, 0, 0},
{-1, 1, 0},
}
for _, tt := range tests {
t.Run(fmt.Sprintf("%d+%d", tt.a, tt.b), func(t *testing.T) {
got := Add(tt.a, tt.b)
if got != tt.want {
t.Errorf("Add() = %d, want %d", got, tt.want)
}
})
}
}
Такой стиль принят в стандартной библиотеке и в сообществе Go.