Go's built-in testing is used by every project; table tests are the house style.
Tests live next to the code in files ending _test.go. A test is a function func TestXxx(t *testing.T) in the same package (or in pkg_test for black-box tests). Run them with go test ./...; add -v for verbose output, -run 'Parse/negative' to filter, -cover for coverage, and -count=1 to bypass the result cache.
*testing.T reports failures:
t.Errorf(...)records a failure and keeps going — preferred, so one run shows all problems.t.Fatalf(...)stops this test immediately — use it when continuing makes no sense.t.Helper()in helper functions makes failures point to the caller's line.t.Cleanup(fn),t.TempDir()andt.Setenv()handle setup and teardown.
The idiomatic shape is a table-driven test: a slice of cases, each with a name, inputs and expected output, looped over with t.Run(tc.name, ...). Each case becomes a subtest that can be run alone and reports separately. Adding a case is one line, which encourages covering edge cases.
Go's style is plain comparisons and clear messages — got X, want Y — rather than assertion libraries. For deep comparisons use reflect.DeepEqual, slices.Equal, or a diff library such as go-cmp.
Calling t.Parallel() lets subtests run concurrently. Example functions (func ExampleAdd() with an // Output: comment) are compiled, run, and shown in the docs, and go test -fuzz adds native fuzzing.
Example
// abs_test.go
package mathx
import "testing"
func Abs(n int) int {
if n < 0 {
return -n
}
return n
}
func TestAbs(t *testing.T) {
tests := []struct {
name string
in int
want int
}{
{"positive", 3, 3},
{"negative", -4, 4},
{"zero", 0, 0},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
if got := Abs(tc.in); got != tc.want {
t.Errorf("Abs(%d) = %d, want %d", tc.in, got, tc.want)
}
})
}
}Remember
- Tests are
TestXxx(t *testing.T)in_test.gofiles; rungo test ./... - Table-driven tests +
t.Runsubtests are the idiomatic structure - Prefer t.Errorf to keep going; t.Fatalf when you can't continue
Watch out for
- Using t.Fatal from a goroutine other than the test's own — it must be called from the test goroutine.