snippetgoModeratepending
Go testing patterns and table-driven tests
Viewed 0 times
table driven testssubtestst.runtest helpergo testing
Problem
Need idiomatic Go testing patterns: table-driven tests, subtests, test helpers, and mocking.
Solution
Go testing patterns:
package calc
import "testing"
// Table-driven test (the Go way)
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
want int
}{
{"positive", 2, 3, 5},
{"negative", -1, -2, -3},
{"zero", 0, 0, 0},
{"mixed", -1, 5, 4},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := Add(tt.a, tt.b)
if got != tt.want {
t.Errorf("Add(%d, %d) = %d, want %d", tt.a, tt.b, got, tt.want)
}
})
}
}
// Test helper (call t.Helper() for better error locations)
func assertEqual(t *testing.T, got, want interface{}) {
t.Helper()
if got != want {
t.Errorf("got %v, want %v", got, want)
}
}
// TestMain for setup/teardown
func TestMain(m *testing.M) {
// Setup (e.g., start test database)
setup()
code := m.Run()
// Teardown
teardown()
os.Exit(code)
}
// Interface-based mocking
type UserStore interface {
GetUser(id string) (*User, error)
}
type mockStore struct {
users map[string]*User
}
func (m *mockStore) GetUser(id string) (*User, error) {
u, ok := m.users[id]
if !ok {
return nil, ErrNotFound
}
return u, nil
}
func TestGetUserHandler(t *testing.T) {
store := &mockStore{
users: map[string]*User{"1": {Name: "Alice"}},
}
handler := NewHandler(store) // Inject mock
// ... test handler ...
}# Run tests
go test ./...
go test -v -run TestAdd # Verbose, specific test
go test -count=1 ./... # Disable test caching
go test -race ./... # Race detector
go test -cover ./... # CoverageWhy
Table-driven tests are idiomatic Go. They're easy to extend with new cases, each case is named for clear failure messages, and subtests can run in parallel.
Context
Writing tests in Go
Revisions (0)
No revisions yet.