Comprehensive Go testing strategies including table-driven tests, testify assertions, gomock interface mocking, benchmark testing, and CI/CD integration
user-invocable
false
disable-model-invocation
true
version
1.0.0
category
toolchain
author
Claude MPM Team
license
MIT
progressive_disclosure
{"entry_point":{"summary":"Master Go testing through table-driven patterns, testify assertions, gomock mocking, benchmarks, and CI integration for production-quality test suites","when_to_use":"Writing comprehensive test suites, setting up CI/CD testing pipelines, mocking external dependencies, performance benchmarking critical paths, ensuring race-free concurrent code","quick_start":"1. Structure tests with table-driven pattern 2. Use testify for assertions 3. Mock interfaces with gomock 4. Benchmark critical paths 5. Integrate coverage in CI/CD"},"token_estimate":{"entry":150,"full":4500}}
Go provides a robust built-in testing framework (testing package) that emphasizes simplicity and developer productivity. Combined with community tools like testify and gomock, Go testing enables comprehensive test coverage with minimal boilerplate.
Key Features:
📋 Table-Driven Tests: Idiomatic pattern for testing multiple inputs
funcBenchmarkAdd(b *testing.B) {
calc := NewCalculator()
for i := 0; i < b.N; i++ {
calc.Add(2, 3)
}
}
funcBenchmarkStringConcatenation(b *testing.B) {
b.Run("plus operator", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = "hello" + "world"
}
})
b.Run("strings.Builder", func(b *testing.B) {
for i := 0; i < b.N; i++ {
var sb strings.Builder
sb.WriteString("hello")
sb.WriteString("world")
_ = sb.String()
}
})
}
Running Benchmarks
# Run all benchmarks
go test -bench=.
# Run specific benchmark
go test -bench=BenchmarkAdd
# With memory allocation stats
go test -bench=. -benchmem
# Compare benchmarks
go test -bench=. -benchmem > old.txt
# Make changes
go test -bench=. -benchmem > new.txt
benchstat old.txt new.txt
funcTestConcurrentMapAccess(t *testing.T) {
cache := NewSafeCache()
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
gofunc(val int) {
defer wg.Done()
cache.Set(fmt.Sprintf("key%d", val), val)
}(i)
}
wg.Wait()
assert.Equal(t, 100, cache.Len())
}
Golden File Testing
Test against expected output files:
funcTestRenderTemplate(t *testing.T) {
output := RenderTemplate("user", User{Name: "Alice"})
goldenFile := "testdata/user_template.golden"if *update {
// Update golden file: go test -update
os.WriteFile(goldenFile, []byte(output), 0644)
}
expected, err := os.ReadFile(goldenFile)
require.NoError(t, err)
assert.Equal(t, string(expected), output)
}
var update = flag.Bool("update", false, "update golden files")
CI/CD Integration
GitHub Actions Example
# .github/workflows/test.ymlname:Testson: [push, pull_request]
jobs:test:runs-on:ubuntu-lateststeps:-uses:actions/checkout@v3-name:SetupGouses:actions/setup-go@v4with:go-version:'1.23'-name:Runtestsrun:gotest-v-race-coverprofile=coverage.out./...-name:Uploadcoverageuses:codecov/codecov-action@v3with:files:./coverage.out-name:Checkcoveragethresholdrun:|
go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//' | \
awk '{if ($1 < 80) exit 1}'
Coverage Enforcement
# Generate coverage report
go test -coverprofile=coverage.out ./...
# View coverage in terminal
go tool cover -func=coverage.out
# Generate HTML report
go tool cover -html=coverage.out -o coverage.html
# Check coverage threshold (fail if < 80%)
go test -coverprofile=coverage.out ./... && \
go tool cover -func=coverage.out | grep total | awk '{if (substr($3, 1, length($3)-1) < 80) exit 1}'
Decision Trees
When to Use Each Testing Tool
Use Standard testing Package When:
Simple unit tests with few assertions
No external dependencies to mock
Performance benchmarking
Minimal dependencies preferred
Use Testify When:
Need readable assertions (assert.Equal vs verbose checks)
Test suites with setup/teardown
Multiple similar test cases
Prefer expressive test code
Use Gomock When:
Testing code with interface dependencies
Need precise call verification (times, order)
Complex mock behavior with multiple scenarios
Type-safe mocking required
Use Benchmarks When:
Optimizing performance-critical code
Comparing algorithm implementations
Detecting performance regressions
Memory allocation profiling
Use httptest When:
Testing HTTP handlers
Mocking external HTTP APIs
Integration testing HTTP clients
Testing middleware chains
Use Race Detector When:
Writing concurrent code
Using goroutines and channels
Shared state across goroutines
CI/CD for all concurrent code
Anti-Patterns to Avoid
❌ Don't Mock Everything
// WRONG: Over-mocking makes tests brittle
mockLogger := mocks.NewMockLogger(ctrl)
mockConfig := mocks.NewMockConfig(ctrl)
mockMetrics := mocks.NewMockMetrics(ctrl)
// Too many mocks = fragile test
✅ Do: Mock Only External Dependencies
// CORRECT: Mock only database, use real logger/config
mockRepo := mocks.NewMockUserRepository(ctrl)
service := NewUserService(mockRepo, realLogger, realConfig)
❌ Don't Test Implementation Details
// WRONG: Testing internal state
assert.Equal(t, "processing", service.internalState)
verification-before-completion: Testing as part of "done"
testing-anti-patterns: Avoid common testing mistakes
Quick Reference
Run Tests
go test ./... # All tests
go test -v ./... # Verbose output
go test -short ./... # Skip slow tests
go test -run TestUserCreate # Specific test
go test -race ./... # With race detector
go test -cover ./... # With coverage
go test -coverprofile=c.out ./... # Coverage file
go test -bench=. -benchmem # Benchmarks with memory
Generate Mocks
go generate ./... # All //go:generate directives
mockgen -source=interface.go -destination=mock.go
Coverage Analysis
go tool cover -func=coverage.out # Coverage per function
go tool cover -html=coverage.out # HTML report
Token Estimate: ~4,500 tokens (entry point + full content)
Version: 1.0.0
Last Updated: 2025-12-03