Everything-claude-code golang-testing
install
source · Clone the upstream repo
git clone https://github.com/affaan-m/everything-claude-code
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/affaan-m/everything-claude-code "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.kiro/skills/golang-testing" ~/.claude/skills/affaan-m-everything-claude-code-golang-testing && rm -rf "$T"
manifest:
.kiro/skills/golang-testing/SKILL.mdsource content
Go Testing
This skill provides comprehensive Go testing patterns extending common testing principles with Go-specific idioms.
Testing Framework
Use the standard
go test with table-driven tests as the primary pattern.
Table-Driven Tests
The idiomatic Go testing pattern:
func TestValidateEmail(t *testing.T) { tests := []struct { name string email string wantErr bool }{ { name: "valid email", email: "user@example.com", wantErr: false, }, { name: "missing @", email: "userexample.com", wantErr: true, }, { name: "empty string", email: "", wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := ValidateEmail(tt.email) if (err != nil) != tt.wantErr { t.Errorf("ValidateEmail(%q) error = %v, wantErr %v", tt.email, err, tt.wantErr) } }) } }
Benefits:
- Easy to add new test cases
- Clear test case documentation
- Parallel test execution with
t.Parallel() - Isolated subtests with
t.Run()
Test Helpers
Use
t.Helper() to mark helper functions:
func assertNoError(t *testing.T, err error) { t.Helper() if err != nil { t.Fatalf("unexpected error: %v", err) } } func assertEqual(t *testing.T, got, want interface{}) { t.Helper() if !reflect.DeepEqual(got, want) { t.Errorf("got %v, want %v", got, want) } }
Benefits:
- Correct line numbers in test failures
- Reusable test utilities
- Cleaner test code
Test Fixtures
Use
t.Cleanup() for resource cleanup:
func testDB(t *testing.T) *sql.DB { t.Helper() db, err := sql.Open("sqlite3", ":memory:") if err != nil { t.Fatalf("failed to open test db: %v", err) } // Cleanup runs after test completes t.Cleanup(func() { if err := db.Close(); err != nil { t.Errorf("failed to close db: %v", err) } }) return db } func TestUserRepository(t *testing.T) { db := testDB(t) repo := NewUserRepository(db) // ... test logic }
Race Detection
Always run tests with the
-race flag to detect data races:
go test -race ./...
In CI/CD:
- name: Test with race detector run: go test -race -timeout 5m ./...
Why:
- Detects concurrent access bugs
- Prevents production race conditions
- Minimal performance overhead in tests
Coverage Analysis
Basic Coverage
go test -cover ./...
Detailed Coverage Report
go test -coverprofile=coverage.out ./... go tool cover -html=coverage.out
Coverage Thresholds
# Fail if coverage below 80% go test -cover ./... | grep -E 'coverage: [0-7][0-9]\.[0-9]%' && exit 1
Benchmarking
func BenchmarkValidateEmail(b *testing.B) { email := "user@example.com" b.ResetTimer() for i := 0; i < b.N; i++ { ValidateEmail(email) } }
Run benchmarks:
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
Mocking
Interface-Based Mocking
type UserRepository interface { GetUser(id string) (*User, error) } type mockUserRepository struct { users map[string]*User err error } func (m *mockUserRepository) GetUser(id string) (*User, error) { if m.err != nil { return nil, m.err } return m.users[id], nil } func TestUserService(t *testing.T) { mock := &mockUserRepository{ users: map[string]*User{ "1": {ID: "1", Name: "Alice"}, }, } service := NewUserService(mock) // ... test logic }
Integration Tests
Build Tags
//go:build integration // +build integration package user_test func TestUserRepository_Integration(t *testing.T) { // ... integration test }
Run integration tests:
go test -tags=integration ./...
Test Containers
func TestWithPostgres(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } // Setup test container ctx := context.Background() container, err := testcontainers.GenericContainer(ctx, ...) assertNoError(t, err) t.Cleanup(func() { container.Terminate(ctx) }) // ... test logic }
Test Organization
File Structure
package/ ├── user.go ├── user_test.go # Unit tests ├── user_integration_test.go # Integration tests └── testdata/ # Test fixtures └── users.json
Package Naming
// Black-box testing (external perspective) package user_test // White-box testing (internal access) package user
Common Patterns
Testing HTTP Handlers
func TestUserHandler(t *testing.T) { req := httptest.NewRequest("GET", "/users/1", nil) rec := httptest.NewRecorder() handler := NewUserHandler(mockRepo) handler.ServeHTTP(rec, req) assertEqual(t, rec.Code, http.StatusOK) }
Testing with Context
func TestWithTimeout(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) defer cancel() err := SlowOperation(ctx) if !errors.Is(err, context.DeadlineExceeded) { t.Errorf("expected timeout error, got %v", err) } }
Best Practices
- Use
for independent testst.Parallel() - Use
to skip slow teststesting.Short() - Use
for temporary directoriest.TempDir() - Use
for environment variablest.Setenv() - Avoid
in test filesinit() - Keep tests focused - one behavior per test
- Use meaningful test names - describe what's being tested
When to Use This Skill
- Writing new Go tests
- Improving test coverage
- Setting up test infrastructure
- Debugging flaky tests
- Optimizing test performance
- Implementing integration tests