golang-testing

Go testing best practices including table-driven tests, test helpers, benchmarking, race detection, coverage analysis, and integration testing patterns. Use when writing or improving Go tests.

144,923 stars
Complexity: easy

About this skill

This skill empowers AI agents to generate or refactor high-quality Go tests following established best practices. It emphasizes the idiomatic Go testing framework using `go test` and promotes table-driven tests for comprehensive scenario coverage. Beyond basic unit testing, the skill incorporates advanced techniques such as writing test helpers, performance benchmarking, detecting data races, analyzing test coverage, and implementing effective integration testing patterns. Designed to be a comprehensive resource for enhancing Go test suites, it ensures the generated Go test code is reliable, maintainable, and aligned with industry standards for production-ready Go applications.

Best use case

Generating new test cases for existing Go functions or packages. Refactoring or improving the quality and coverage of existing Go test files. Adding performance benchmarks to critical Go code paths. Ensuring new Go code adheres to testing best practices from the outset. Identifying potential race conditions in Go concurrency patterns and suggesting tests for them. Developing integration tests for Go services and APIs.

Go testing best practices including table-driven tests, test helpers, benchmarking, race detection, coverage analysis, and integration testing patterns. Use when writing or improving Go tests.

Well-structured, idiomatic Go test code using the standard `testing` package. Comprehensive test cases covering various scenarios via table-driven tests. Benchmarking functions to measure code performance. Effective test helpers to reduce boilerplate and improve test readability. Guidance on detecting race conditions and analyzing test coverage. Patterns for effective integration tests, enhancing application reliability.

Practical example

Example input

Generate Go tests for the following `CalculateDiscount` function. It should include table-driven tests covering positive, zero, and edge-case discount percentages. Also, add a benchmark for its performance.

```go
package main

import "fmt"

func CalculateDiscount(originalPrice float64, discountPercent float64) (float64, error) {
    if discountPercent < 0 || discountPercent > 100 {
        return 0, fmt.Errorf("discount percentage must be between 0 and 100")
    }
    discountAmount := originalPrice * (discountPercent / 100)
    finalPrice := originalPrice - discountAmount
    return finalPrice, nil
}
```

Example output

```go
package main

import (
	"math"
	"testing"
)

// Helper function to compare floats with a tolerance
func assertFloatEquals(t *testing.T, got, want float64, msg string) {
	t.Helper()
	if math.Abs(got-want) > 0.001 { // Using a small tolerance for float comparison
		t.Errorf("%s: got %f, want %f", msg, got, want)
	}
}

func TestCalculateDiscount(t *testing.T) {
	tests := []struct {
		name            string
		originalPrice   float64
		discountPercent float64
		wantFinalPrice  float64
		wantErr         bool
	}{
		{
			name:            "valid discount 10%",
			originalPrice:   100.0,
			discountPercent: 10.0,
			wantFinalPrice:  90.0,
			wantErr:         false,
		},
		{
			name:            "valid discount 0%",
			originalPrice:   100.0,
			discountPercent: 0.0,
			wantFinalPrice:  100.0,
			wantErr:         false,
		},
		{
			name:            "valid discount 100%",
			originalPrice:   100.0,
			discountPercent: 100.0,
			wantFinalPrice:  0.0,
			wantErr:         false,
		},
		{
			name:            "invalid discount negative",
			originalPrice:   100.0,
			discountPercent: -5.0,
			wantFinalPrice:  0.0,
			wantErr:         true,
		},
		{
			name:            "invalid discount over 100%",
			originalPrice:   100.0,
			discountPercent: 105.0,
			wantFinalPrice:  0.0,
			wantErr:         true,
		},
		{
			name:            "zero original price",
			originalPrice:   0.0,
			discountPercent: 10.0,
			wantFinalPrice:  0.0,
			wantErr:         false,
		},
		{
			name:            "fractional discount",
			originalPrice:   99.99,
			discountPercent: 12.5,
			wantFinalPrice:  87.49125,
			wantErr:         false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			gotFinalPrice, err := CalculateDiscount(tt.originalPrice, tt.discountPercent)

			if (err != nil) != tt.wantErr {
				t.Errorf("CalculateDiscount() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if !tt.wantErr {
				assertFloatEquals(t, gotFinalPrice, tt.wantFinalPrice, "CalculateDiscount() final price mismatch")
			}
		})
	}
}

func BenchmarkCalculateDiscount(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		_, _ = CalculateDiscount(100.0, 10.0)
	}
}
```

When to use this skill

  • When asked to 'Write Go tests for `funcName` adhering to table-driven patterns.'
  • When prompted to 'Improve the test coverage for this Go package.'
  • When requesting to 'Add benchmarks for `functionX` in `fileName.go`.'
  • When needing to 'Generate integration tests for this Go service's API endpoints.'

When not to use this skill

  • When the task does not involve Go language or testing (e.g., Python development, general writing).
  • For generating production Go application code directly (this skill is focused on testing).
  • If the primary goal is to set up a CI/CD pipeline for Go testing (though it provides the content for tests within it).

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/golang-testing/SKILL.md --create-dirs "https://raw.githubusercontent.com/affaan-m/everything-claude-code/main/.kiro/skills/golang-testing/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/golang-testing/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How golang-testing Compares

Feature / Agentgolang-testingStandard Approach
Platform SupportClaudeLimited / Varies
Context Awareness High Baseline
Installation ComplexityeasyN/A

Frequently Asked Questions

What does this skill do?

Go testing best practices including table-driven tests, test helpers, benchmarking, race detection, coverage analysis, and integration testing patterns. Use when writing or improving Go tests.

Which AI agents support this skill?

This skill is designed for Claude.

How difficult is it to install?

The installation complexity is rated as easy. You can find the installation instructions above.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

Related Guides

SKILL.md Source

# 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:

```go
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:

```go
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:

```go
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:

```bash
go test -race ./...
```

**In CI/CD:**
```yaml
- 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

```bash
go test -cover ./...
```

### Detailed Coverage Report

```bash
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
```

### Coverage Thresholds

```bash
# Fail if coverage below 80%
go test -cover ./... | grep -E 'coverage: [0-7][0-9]\.[0-9]%' && exit 1
```

## Benchmarking

```go
func BenchmarkValidateEmail(b *testing.B) {
    email := "user@example.com"

    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        ValidateEmail(email)
    }
}
```

**Run benchmarks:**
```bash
go test -bench=. -benchmem
```

**Compare benchmarks:**
```bash
go test -bench=. -benchmem > old.txt
# make changes
go test -bench=. -benchmem > new.txt
benchstat old.txt new.txt
```

## Mocking

### Interface-Based Mocking

```go
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
//go:build integration
// +build integration

package user_test

func TestUserRepository_Integration(t *testing.T) {
    // ... integration test
}
```

**Run integration tests:**
```bash
go test -tags=integration ./...
```

### Test Containers

```go
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

```go
// Black-box testing (external perspective)
package user_test

// White-box testing (internal access)
package user
```

## Common Patterns

### Testing HTTP Handlers

```go
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

```go
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

1. **Use `t.Parallel()`** for independent tests
2. **Use `testing.Short()`** to skip slow tests
3. **Use `t.TempDir()`** for temporary directories
4. **Use `t.Setenv()`** for environment variables
5. **Avoid `init()`** in test files
6. **Keep tests focused** - one behavior per test
7. **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

Related Skills

swift-protocol-di-testing

144923
from affaan-m/everything-claude-code

基于协议的依赖注入,用于可测试的Swift代码——使用聚焦协议和Swift Testing模拟文件系统、网络和外部API。

DevelopmentClaude

perl-testing

144923
from affaan-m/everything-claude-code

使用Test2::V0、Test::More、prove runner、模拟、Devel::Cover覆盖率和TDD方法的Perl测试模式。

DevelopmentClaude

rust-testing

144923
from affaan-m/everything-claude-code

Rust testing patterns including unit tests, integration tests, async testing, property-based testing, mocking, and coverage. Follows TDD methodology.

DevelopmentClaude

kotlin-testing

144923
from affaan-m/everything-claude-code

Kotest, MockK, coroutine testi, property-based testing ve Kover coverage ile Kotlin test kalıpları. İdiomatic Kotlin uygulamalarıyla TDD metodolojisini takip eder.

DevelopmentClaude

cpp-testing

144923
from affaan-m/everything-claude-code

C++ テストの作成/更新/修正、GoogleTest/CTest の設定、失敗またはフレーキーなテストの診断、カバレッジ/サニタイザーの追加時にのみ使用します。

DevelopmentClaude

python-testing

144923
from affaan-m/everything-claude-code

Python testing best practices using pytest including fixtures, parametrization, mocking, coverage analysis, async testing, and test organization. Use when writing or improving Python tests.

DevelopmentClaude

golang-patterns

144923
from affaan-m/everything-claude-code

Go-specific design patterns and best practices including functional options, small interfaces, dependency injection, concurrency patterns, error handling, and package organization. Use when working with Go code to apply idiomatic Go patterns.

DevelopmentClaude

workspace-surface-audit

144923
from affaan-m/everything-claude-code

Audit the active repo, MCP servers, plugins, connectors, env surfaces, and harness setup, then recommend the highest-value ECC-native skills, hooks, agents, and operator workflows. Use when the user wants help setting up Claude Code or understanding what capabilities are actually available in their environment.

DevelopmentClaude

safety-guard

144923
from affaan-m/everything-claude-code

Use this skill to prevent destructive operations when working on production systems or running agents autonomously.

DevelopmentClaude

repo-scan

144923
from affaan-m/everything-claude-code

Cross-stack source code asset audit — classifies every file, detects embedded third-party libraries, and delivers actionable four-level verdicts per module with interactive HTML reports.

DevelopmentClaude

project-flow-ops

144923
from affaan-m/everything-claude-code

Operate execution flow across GitHub and Linear by triaging issues and pull requests, linking active work, and keeping GitHub public-facing while Linear remains the internal execution layer. Use when the user wants backlog control, PR triage, or GitHub-to-Linear coordination.

DevelopmentClaude

manim-video

144923
from affaan-m/everything-claude-code

Build reusable Manim explainers for technical concepts, graphs, system diagrams, and product walkthroughs, then hand off to the wider ECC video stack if needed. Use when the user wants a clean animated explainer rather than a generic talking-head script.

DevelopmentClaude