Quick tip: Easy test assertions with Go generics
Now that Go 1.18 has been released with support for generics, it's easier than ever to create helper functions for your test assertions.
Using helpers for your test assertions can help to:
- Make your test functions clean and clear;
- Keep test failure messages consistent;
- And reduce the potential for errors in your code due to typos.
To illustrate this, let's say that you have a simple greet()
function that you want to test:
package main
import "fmt"
func greet(name string) (string, int) {
greeting := fmt.Sprintf("Hello %s", name)
// Return the greeting and its length (in bytes).
return greeting, len(greeting)
}
In the past, your test for the greet()
function would probably look something like this:
package main
import "testing"
func TestGreet(t *testing.T) {
greeting, greetingLength := greet("Alice")
// Test assertion to check the returned greeting string.
if greeting != "Hello Alice" {
t.Errorf("got: %s; want: %s", greeting, "Hello Alice")
}
// Test assertion to check the returned greeting length.
if greetingLength != 11 {
t.Errorf("got: %d; want: %d", greetingLength, 11)
}
}
With Go 1.18, we can use generics and the comparable
constraint to create an Equal()
helper function which carries out our test assertions. Personally, I like to put this in a reusable assert
package.
Like so:
package assert
import "testing"
func Equal[T comparable](t *testing.T, actual, expected T) {
t.Helper()
if actual != expected {
t.Errorf("got: %v; want: %v", actual, expected)
}
}
And with that in place, the TestGreet()
test can be simplified like so:
package main
import (
"testing"
"your.module.path/assert" // Import your assert package.
)
func TestGreet(t *testing.T) {
greeting, greetingLength := greet("Alice")
assert.Equal(t, greeting, "Hello Alice")
assert.Equal(t, greetingLength, 11)
}