Table driven tests are a popular model for testing in Go and a clear improvement to traditional testing of one function per case. However, there’s an alternative style that can often be clearer than table driven tests that relies on function closures.

I’ll reference the example code on Dave Cheney’s post Prefer table driven tests for my examples.

The original way

The code we want to test is a function that splits strings.

The original way to test code like this was to create different test functions for each case. Here are two tests: one for a wrong separator and another for no separator.

Table driven test example

As a table driven test, we create a struct object to hold the common parts of the test case. This has many advantages: the biggest of which is that we can add more test cases easily.

The common parts of traditional table driven tests are

a structure to represent the test case

a loop around an array or map of the structure

testing logic inside the main body of the loop

Closure driven test example

We can make a closure of our main testing body and rewrite the above code.

The common parts of closure driven tests are

Defined test case parameters as function parameters rather than struct parameters

A function that returns func (t *testing.T) , often inline with the test

, often inline with the test Inline executions of cases rather than a loop

The most important part is that we can use the return value of splitEquals directly as the second parameter to t.Run .

Comparing closure driven tests to table driven tests

A few advantages stick out for closure driven tests.

TestSplit2 has fewer lines of code, but is still easy to read

has fewer lines of code, but is still easy to read It’s obvious how to add other splitNotEquals or splitContains closures in a way that doesn’t require another for loop

or closures in a way that doesn’t require another for loop Traditional Go tests name the thing they are testing TestSplit and the test input simple , but give no name to the logic used for testing. Closure driven tests add the name splitEquals to your code.

and the test input , but give no name to the logic used for testing. Closure driven tests add the name to your code. We avoid the unnatural compact one line struct{} style of table driven tests

Which you use is more of a personal choice, but I’ve found closure driven tests easier to extend and develop iteratively and am using them for most my current code.