Go testing best practices including table-driven tests, race detection, test coverage, and mocking strategies. Use when writing or reviewing Go tests.
Installation
Details
Usage
After installing, this skill will be available to your AI coding assistant.
Verify installation:
npx agent-skills-cli listSkill Instructions
name: go-testing description: Go testing best practices including table-driven tests, race detection, test coverage, and mocking strategies. Use when writing or reviewing Go tests.
Go Testing
Expert guidance for writing maintainable, effective Go tests.
Quick Reference
| Pattern | When to Use | Structure |
|---|---|---|
| Table-driven tests | Multiple inputs/outputs | []struct with test cases |
| Subtests | Related test variants | t.Run() for each case |
| TestMain | Global setup/teardown | func TestMain(m *testing.M) |
| t.Cleanup | Per-test cleanup | Deferred cleanup function |
| fakes/fuzzing | Random input testing | testing.F, f.Fuzz() |
| Race detector | Concurrent code | go test -race |
| Coverage | Ensuring thoroughness | go test -cover |
What Do You Need?
- Test structure - Table-driven, subtests, organization
- Mocking - Fakes, interfaces, test doubles
- Concurrency testing - Race detector, parallel tests
- Coverage - Measuring and improving test coverage
- Test data - Fixtures, golden files, test helpers
Specify a number or describe your testing scenario.
Routing
| Response | Reference to Read |
|---|---|
| 1, "table", "driven", "multiple cases" | table-driven.md |
| 2, "mock", "fake", "interface" | mocking.md |
| 3, "race", "concurrent", "parallel" | concurrency.md |
| 4, "coverage", "measure", "thorough" | coverage.md |
| 5, general testing | Read relevant references |
Critical Rules
- Table-driven for variations: Use for multiple inputs/outputs
- Descriptive test names: TestFunctionName_State format
- t.Cleanup for cleanup: Prefer over defer in tests
- Run with -race: Must pass for concurrent code
- Avoid mocking when possible: Use real implementations or fakes
- Tests should fail for the right reason: Not due to flakiness
Test Template
func TestFunctionName(t *testing.T) {
tests := []struct {
name string
input InputType
want WantType
wantErr bool
errIs error
}{
{
name: "successful case",
input: InputType{...},
want: WantType{...},
wantErr: false,
},
{
name: "validation error",
input: InputType{...},
wantErr: true,
errIs: ErrValidation,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := FunctionName(tt.input)
if (err != nil) != tt.wantErr {
t.Errorf("FunctionName() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.errIs != nil && !errors.Is(err, tt.errIs) {
t.Errorf("FunctionName() error = %v, wantIs %v", err, tt.errIs)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("FunctionName() = %v, want %v", got, tt.want)
}
})
}
}
Test Organization
project/
βββ internal/
β βββ service/
β β βββ service.go
β β βββ service_test.go
β β βββ service_golden_test.go
β βββ service/
β βββ mocks/ # Generated mocks (if needed)
β βββ testdata/ # Golden files, fixtures
βββ testutil/
βββ setup.go # Test helpers
βββ fixtures.go # Shared test data
Common Testing Patterns
HTTP Handlers
func TestHandler(t *testing.T) {
tests := []struct {
name string
method string
body string
wantStatus int
wantBody string
}{
{"valid POST", "POST", `{"foo":"bar"}`, 200, `{"result":"ok"}`},
{"invalid JSON", "POST", `{`, 400, ""},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest(tt.method, "/test", strings.NewReader(tt.body))
rec := httptest.NewRecorder()
Handler(rec, req)
if rec.Code != tt.wantStatus {
t.Errorf("status = %d, want %d", rec.Code, tt.wantStatus)
}
})
}
}
Using t.Cleanup
func TestWithCleanup(t *testing.T) {
// Setup
db := openTestDB(t)
t.Cleanup(func() {
db.Close() // Runs even if test fails
})
// Test code...
}
Race Detection
# Run tests with race detector
go test -race ./...
# Run specific test with race detector
go test -race -run TestConcurrentFunction
Reference Index
| File | Topics |
|---|---|
| table-driven.md | Table structure, subtests, naming |
| mocking.md | Interfaces, fakes, mocking libraries |
| concurrency.md | Race detector, parallel tests, sync |
| coverage.md | -cover, -coverprofile, thresholds |
Success Criteria
Tests are good when:
- Table-driven tests cover variations
- Race detector passes (-race)
- Coverage is meaningful (not just high numbers)
- Tests are readable and maintainable
- t.Cleanup used for resource cleanup
- Test failures are clear about what went wrong
More by jovermier
View allNext.js performance optimizations including next/image, next/font, dynamic imports, caching strategies, and bundle optimization. Use when optimizing Next.js apps for speed or Core Web Vitals.
Playwright Page Object Model including page classes, fixtures, helpers, and test organization. Use when structuring Playwright E2E tests or organizing test code.
Automatically discover and install relevant skills from SkillsMP and other sources
GraphQL schema design including types, fields, pagination, nullability, naming conventions, and descriptions. Use when designing or modifying GraphQL schemas.
