Idiomatic Go Testing: Table Driven Test
Introduction
Recently, while writing Go tests I noticed a widely praised convention in the official docs and community: TableDrivenTests. I always thought tests should stay simple and stupid, but this approach made me think of one of the three virtues of programmers: “laziness”.
What is Table Driven Testing
Basically it stores the states used in tests into a slice and runs the tests uniformly in a loop:
func Add(a, b int) int { return a + b}
func Test_Add(t *testing.T) { tests := []struct { name string a, b int expected int }{ {"Add positive numbers", 1, 1, 2}, {"Add zero", 1, 0, 1}, {"Add negative numbers", -1, -1, -2}, }
for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := Add(tt.a, tt.b) if got != tt.expected { t.Errorf("Add(%d, %d) = %d, Excepted %d", tt.a, tt.b, got, tt.expected) } }) }}Compared with the previous approach
In a normal test each case must duplicate the same test boilerplate:
func Test_Add(t *testing.T) { t.Run("Add positive numbers", func(t *testing.T) { got := Add(1, 1) if got != 2 { t.Errorf("Add(1, 1) = %d, Expected 2", got) } })
t.Run("Add zero", func(t *testing.T) { got := Add(1, 0) if got != 1 { t.Errorf("Add(1, 0) = %d, Expected 1", got) } })
t.Run("Add negative numbers", func(t *testing.T) { got := Add(-1, -1) if got != -2 { t.Errorf("Add(-1, -1) = %d, Expected -2", got) } })}Each time you add a test case you have to copy the test logic again, whereas Table Driven Test separates “test logic” and “test data”. Editing cases only requires adding another struct entry to the slice; the test logic itself doesn’t need to be touched.
Conclusion
I’m curious why this testing pattern isn’t as common in other languages. Perhaps it’s usually just a convenience provided by test frameworks, and the Go community has a peculiar obsession with keeping programs simple.
test.each([ ["Adding positive numbers", 1, 1, 2], ["Adding zero", 1, 0, 1], ["Adding negative numbers", -1, -1, -2],])("%s", (name, a, b, expected) => { expect(add(a, b)).toBe(expected);});