Don't Abuse Table-Driven Test

— 3 minute read

Table-driven test is a very popular testing pattern in Go. It works by defining test cases in a table. The test can iterate through the test cases to perform the necessary setup and assertion. It's a very handy way to reduce duplication in tests..

func TestMapErrorCode(t *testing.T) {
tests := []struct{
code int

werr error
} {
{400, myerrors.BadRequest},
{403, myerrors.Forbidden},
{500, myerrors.InternalServerError},
}

for _, tt := range tests {
t.Run(tt.code, func(t *testing.T) {
err := MapErrorCode(tt.code)
if err != tt.werr {
t.Errorf("got %v, want %v", err, tt.werr)
}
})
}
}

However, it's easy to misuse table-driven test by setting up a complicated table. You know your table is too large when:

  • There are fields in the table that are only used in some of the test cases
  • You have a lot of conditions to set up your test that's controlled by the table

If the table grew too large, consider splitting it up into multiple tests. Some duplication is still better than unreadable code.