notexOPENOverview
Notex/Languages/Cleanup, Context, and Helper
05.06LESSON 06 OF 29 · 2 MIN READ

Cleanup, Context, and Helper

Always free to read

The Cleanup method on *testing.T is used to clean up temporary resources created for a single test. This method has a single parameter: a function with no input parameters or return values. The function runs when the test completes. For simple tests, you can achieve the same result by using a defer statement, but Cleanup is useful when tests rely on helper functions to set up sample data. It’s fine to call Cleanup multiple times. Just like defer, the functions are invoked in last-added, first-called order. Example 6-1 demonstrates a test helper function that uses Cleanup:

Example 6-1. A Test Helper with t.Cleanup and t.Helper

func TestAddressQuery(t *testing.T) {
    db := setupDB(t, "address")
    address, err := FindAddress(t.Context(), db, "Fred")
    if err != nil {
        t.Error(err)
    }
    if address.Country != "Australia" {
        t.Error("wrong country")
    }
}

func setupDB(t *testing.T, tableName string) *sql.DB {
    t.Helper()
    db, err := sql.Open("ramsql", tableName)
    if err != nil {
        t.Fatal("error creating database", err)
    }
    t.Cleanup(func() { db.Close() })
    return db
}

Functions like setupDB are referred to as test helpers since they set up or tear down the state needed to properly test code, but do no testing themselves. If something goes wrong it is usually a fatal error, as the test cannot continue without valid initial conditions. To mark the function as a test helper, it is idiomatic to pass a *testing.T instance to these functions and add a call to t.Helper as the first line. When t.Helper is called, it modifies the output of any calls to t.Error or t.Fatal within the test helper. Rather than print the filename and line number of the line in the test helper, the filename and line number of the line in the test function that called the test helper is displayed. This is useful when a helper function is called from multiple tests; you’ll see the name of the test and the line where the helper was called in the error output.

In this example, the helper function setupDB creates a per-test database connection. Inside of setupDB, Cleanup is called to close the database connection when the test exits. We can’t use a defer here, because defer runs when a function exits and we want to close the connection when the test ends.

Another thing to notice is in TestAddressQuery. The context that’s passed into FindAddress comes from the t.Context method. This is a special context that is automatically canceled when the test exits. Using it allows any code being tested to shut down properly when the test ends. Prefer using t.Context in tests over context.Background.

You can find this sample code in the examples/helper directory has an example. It is also available on the Go Playground. Change "ramsql" to some other string and run the test with the t.Helper() line commented and then uncommented to see the difference it makes in the error output.

Progress is saved on this device.
KEEP EXPLORING

One note leads to another.

Back to the library →
⌕
Search across the entire library ⌘ K