Just like when we're writing "real" code, our tests sometimes need helper functions. These helper functions are called "test helpers". Test helpers might setup, or teardown, or provision resources for the test. They can be use to write assertions or to mock out external dependencies.
Defining Test Helpers
Test helpers functions in Go are just like any other function. The difference is that they are only defined in your tests. While not required, it is recommended that you take the testing.TB interface, Listing 7.1, as the first argument to your test helper function. This interface is the common set of functions to both the testing.T and testing.B, used for benchmarking, types.
Let's define some test helpers to help clean up tests in Listing 7.2. We will create helpers to create the different Store implementations we need for the test.
First, in Listing 7.3, we create two helper functions. The first, noData(testing.TB) returns a &Store that does not have any data. The second, withData(testing.TB) returns a &Store that has its data field properly initialized.
In Listing 7.4 we declare the withUsers helper function needed to clean up the tests. At the moment, however, we are unable to implement the withUsers test helper so we can call the testing.TB.Fatal method on the passed in testing.TB to let Go that we haven't implemented this helper yet.
Finally, in Listing 7.5, we can update our tests to use the new test helpers, passing in the testing.T argument from the test to the helper function.
As seen in Listing 7.6, because we have yet to implement the withUsers helper our tests will fail.
When the test fails it reported the test failure as inside the withUsers helper, Listing 7.4, and not within the test itself. This can make it difficult to debug the test failure.
Marking a Function as a Helper
In order to get Go to report the correct line number, inside of the test not the helper, we need to tell Go that the withData function is a test helper. To do that we must use the testing.TB.Helper, Listing 7.7, method inside of our test helpers.
Now, when the test fails, in Listing 7.8, the line number reported will be the line number inside the test that failed, not the line number inside the helper.
Cleaning up a Helper
It is very common that a test helper, or even a test itself, needs to clean up some resources when done. In order to do that we need to use the testing.TB.Cleanup method, Listing 7.9. With testing.TB.Cleanup we can pass in a function that will be called, automatically, when the test is done.
In Listing 7.10, we implement the withUsers helper function. In it, we use the testing.TB.Cleanup method to clean up the users we created.
Clarifying "Cleanup" vs. "defer"
While the testing.TB.Cleanup method might seem like a fancy defer statement, it is actually a different concept. When a function is deferred that function will be called when its parent function returns. In the case of testing.TB.Cleanup, the testing.TB.Cleanup function will be called when the test is done.