Use the testing package by writing functions that start with Test and accept a *testing.T argument, then run them with go test. The test runner executes these functions and reports failures if assertions fail or panics occur.
package main
import "testing"
func TestAdd(t *testing.T) {
if 1+1 != 2 {
t.Error("expected 2")
}
}
Run the tests from the command line:
go test
For table-driven tests, define a slice of test cases and loop through them:
func TestAddTable(t *testing.T) {
tests := []struct {
a, b, want int
}{
{1, 2, 3},
{0, 0, 0},
}
for _, tt := range tests {
t.Run(fmt.Sprintf("%d+%d", tt.a, tt.b), func(t *testing.T) {
if got := tt.a + tt.b; got != tt.want {
t.Errorf("got %d, want %d", got, tt.want)
}
})
}
}
Use t.Skip to skip tests conditionally and t.Fatalf to stop a test immediately on failure:
func TestConditional(t *testing.T) {
if someCondition {
t.Skip("skipping due to condition")
}
if badResult {
t.Fatalf("critical failure: %v", badResult)
}
}
For benchmarking, write functions starting with Benchmark that accept a *testing.B argument:
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = 1 + 1
}
}
Run benchmarks with:
go test -bench=.
For fuzzing, write functions starting with Fuzz that accept a *testing.F argument:
func FuzzAdd(f *testing.F) {
f.Add(1, 2)
f.Fuzz(func(t *testing.T, a, b int) {
_ = a + b
})
}
Run fuzz tests with:
go test -fuzz=FuzzAdd
Use //go:debug directives in *_test.go files to control runtime behavior during tests:
//go:debug panicnil=1
package main
import "testing"
func TestPanicNil(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Logf("caught panic: %v", r)
}
}()
panic(nil)
}
Verify default GODEBUG settings for your test package with:
go list -f '{{.DefaultGODEBUG}}' ./my/test/package