Part 5 · 1 chapters · ~8 min

Tooling and Testing

go test with table-driven tests and subtests, testify and when not to need it, httptest for handlers, benchmarks and benchstat, native fuzzing, go vet, staticcheck and golangci-lint, integration tests with testcontainers-go, govulncheck, and dependency management with go mod.

10

Built-in tools

code
func TestFee(t *testing.T) {
	cases := []struct{ name string; amount, want int64; wantErr bool }{
		{"minimum applies", 100_000, 1_000, false},
		{"half percent", 5_000_000, 25_000, false},
		{"zero is invalid", 0, 0, true},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			got, err := fee(c.amount)
			if (err != nil) != c.wantErr { t.Fatalf("err = %v", err) }
			if got != c.want { t.Fatalf("got %d, want %d", got, c.want) }
		})
	}
}
// handlers: httptest.NewRecorder() + router.ServeHTTP(rec, req), no network needed
TOOLING THAT SHIPS WITH GO
most of what other ecosystems install, built in
go testUnit tests, table-driven; -race,-cover, -run, -count=1; subtestswith t.Run.go test -benchBenchmarks with b.N and -benchmemfor allocations per operation.go test -fuzzNative fuzzing (1.18+): randominputs, crashes saved asregression cases.go vet + staticcheckSuspicious constructs; staticcheckand golangci-lint add many morechecks.gofmt / goimportsOne formatting style for everyone;no debates.govulncheckKnown vulnerabilities independencies, filtered to code youactually call.
swipe the figure sideways, or tap expand for full screen
1/6
tests
Tests live beside code in _test.go files. Table-driven tests list cases as data and loop over them with t.Run for named subtests.
table-driven, t.Run subtestsgo test ./... runs them all