go-testing

Use when writing, reviewing, or debugging Go tests and benchmarks. Covers table-driven tests, parallel execution, go-cmp, T.Context, T.Chdir, b.Loop, synctest for deterministic concurrency testing, and test failure messages.

6 stars

Best use case

go-testing is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Use when writing, reviewing, or debugging Go tests and benchmarks. Covers table-driven tests, parallel execution, go-cmp, T.Context, T.Chdir, b.Loop, synctest for deterministic concurrency testing, and test failure messages.

Teams using go-testing should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/go-testing/SKILL.md --create-dirs "https://raw.githubusercontent.com/saisudhir14/golang-agent-skill/main/skills/go-testing/SKILL.md"

Manual Installation

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

How go-testing Compares

Feature / Agentgo-testingStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Use when writing, reviewing, or debugging Go tests and benchmarks. Covers table-driven tests, parallel execution, go-cmp, T.Context, T.Chdir, b.Loop, synctest for deterministic concurrency testing, and test failure messages.

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

Production-grade testing patterns for Go.

## Table-Driven Tests with Parallel Execution

```go
func TestSplit(t *testing.T) {
    tests := []struct {
        name  string
        input string
        sep   string
        want  []string
    }{
        {name: "simple", input: "a/b/c", sep: "/", want: []string{"a", "b", "c"}},
        {name: "empty", input: "", sep: "/", want: []string{""}},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            t.Parallel()
            got := strings.Split(tt.input, tt.sep)
            if diff := cmp.Diff(tt.want, got); diff != "" {
                t.Errorf("Split() mismatch (-want +got):\n%s", diff)
            }
        })
    }
}
```

## T.Context and T.Chdir (Go 1.24+)

```go
func TestWithContext(t *testing.T) {
    // T.Context returns a context canceled after test completes
    // but before cleanup functions run
    ctx := t.Context()
    result, err := doWork(ctx)
    if err != nil {
        t.Fatal(err)
    }
}

func TestWithChdir(t *testing.T) {
    // T.Chdir changes working directory for duration of test
    // and automatically restores it after
    t.Chdir("testdata")
    data, err := os.ReadFile("input.txt")
    // ...
}
```

## Benchmark with b.Loop (Go 1.24+)

```go
// Old way - error prone
func BenchmarkOld(b *testing.B) {
    input := setupInput() // counted in benchmark time!
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        process(input)    // compiler might optimize away
    }
}

// Go 1.24+ - preferred
func BenchmarkNew(b *testing.B) {
    input := setupInput() // setup runs once, excluded from timing
    for b.Loop() {
        process(input)    // compiler cannot optimize away
    }
}
```

Benefits of `b.Loop()`:
- Setup code runs exactly once per `-count`, automatically excluded from timing
- No need to call `b.ResetTimer()`
- Function call parameters and results are kept alive, preventing compiler optimization

## Testing Concurrent Code with synctest (Go 1.25+)

The `testing/synctest` package provides deterministic testing for concurrent code using synthetic time.

```go
import "testing/synctest"

func TestTimeout(t *testing.T) {
    synctest.Test(t, func(t *testing.T) {
        ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)
        defer cancel()

        time.Sleep(4 * time.Second) // instant in real time
        if err := ctx.Err(); err != nil {
            t.Fatalf("unexpected timeout: %v", err)
        }

        time.Sleep(2 * time.Second)
        if ctx.Err() != context.DeadlineExceeded {
            t.Fatal("expected deadline exceeded")
        }
    })
}
```

Key concepts:
- `synctest.Test` creates an isolated "bubble" with synthetic time
- Time only advances when all goroutines in the bubble are blocked
- `synctest.Wait()` waits for all goroutines to be durably blocked

```go
func TestPeriodicTask(t *testing.T) {
    synctest.Test(t, func(t *testing.T) {
        var count atomic.Int64
        ctx, cancel := context.WithCancel(t.Context())

        go func() {
            ticker := time.NewTicker(100 * time.Millisecond)
            defer ticker.Stop()
            for {
                select {
                case <-ctx.Done():
                    return
                case <-ticker.C:
                    count.Add(1)
                }
            }
        }()

        time.Sleep(350 * time.Millisecond)
        synctest.Wait()
        cancel()
        synctest.Wait()

        if got := count.Load(); got != 3 {
            t.Errorf("got %d ticks, want 3", got)
        }
    })
}
```

**Restrictions in synctest bubbles:** Do not call `t.Run()`, `t.Parallel()`, or `t.Deadline()`.

## Use go-cmp for Comparisons

Prefer `github.com/google/go-cmp/cmp` over `reflect.DeepEqual`.

```go
if diff := cmp.Diff(want, got); diff != "" {
    t.Errorf("mismatch (-want +got):\n%s", diff)
}

// With options
if diff := cmp.Diff(want, got, cmpopts.IgnoreUnexported(User{})); diff != "" {
    t.Errorf("mismatch (-want +got):\n%s", diff)
}
```

## Useful Test Failures

Include: what was wrong, inputs, actual result, expected result.

```go
// Wrong
if got != want { t.Error("wrong result") }

// Correct
if got != want { t.Errorf("Foo(%q) = %d; want %d", input, got, want) }
```

## Use t.Fatal for Setup Failures

```go
f, err := os.CreateTemp("", "test")
if err != nil {
    t.Fatal("failed to set up test")
}
```

## Interfaces Belong to Consumers

Define interfaces in the package that uses them, not the package that implements them.

```go
// Producer returns concrete type
package producer
type Thinger struct{}
func NewThinger() *Thinger { return &Thinger{} }

// Consumer defines interface it needs
package consumer
type Thinger interface { Thing() bool }
func Process(t Thinger) { }
```

Related Skills

go-security

6
from saisudhir14/golang-agent-skill

Use when writing, reviewing, or auditing Go code for security. Covers input validation, SQL injection prevention, path traversal, secrets management, cryptography, HTTP security headers, and dependency scanning.

go-project-layout

6
from saisudhir14/golang-agent-skill

Use when starting a new Go project, organizing packages, or restructuring an existing Go codebase. Covers standard directory layout, package design, Makefile targets, Dockerfile patterns, and module setup.

go-performance

6
from saisudhir14/golang-agent-skill

Use when writing, reviewing, or optimizing Go code for performance. Covers string operations, memory allocation, preallocating slices and maps, strings.Builder, strconv, container-aware GOMAXPROCS, and runtime considerations for Go 1.25.

go-linting

6
from saisudhir14/golang-agent-skill

Use when setting up linting, configuring golangci-lint, or fixing linter warnings in Go projects. Provides recommended linter sets, golangci-lint configuration, CI integration, and Makefile targets.

go-error-handling

6
from saisudhir14/golang-agent-skill

Use when writing, reviewing, or debugging Go error handling code. Covers error wrapping, sentinel errors, custom error types, error joining, single handling, and error flow patterns. Based on Google and Uber style guides.

go-concurrency

6
from saisudhir14/golang-agent-skill

Use when writing, reviewing, or debugging concurrent Go code. Covers goroutine lifecycle management, channels, errgroup, mutexes, atomics, sync.Map, and synchronous-first design. Based on Google and Uber style guides.

go-code-review

6
from saisudhir14/golang-agent-skill

Use when reviewing Go code or preparing code for review. Quick-reference checklist covering naming, error handling, concurrency, testing, imports, documentation, and common pitfalls. Based on Go Wiki CodeReviewComments.

golang

6
from saisudhir14/golang-agent-skill

Use when writing, reviewing, or refactoring Go code. Provides production best practices for Go covering error handling, concurrency, naming, testing, performance, generics, iterators, and common pitfalls. Distilled from Google Go Style Guide, Uber Go Style Guide, Effective Go, and Go Code Review Comments. Updated for Go 1.25.

testing

9
from jkomoros/community-patterns

Test patterns with Playwright browser automation. Navigate to deployed patterns, interact with UI elements, verify functionality. Use when testing patterns after deployment or when debugging pattern behavior in browser.

cw-testing

9
from sighup/claude-workflow

E2E testing with auto-fix. Generates tests from specs, executes in isolated sub-agents, and auto-fixes application bugs. This skill should be used after implementation to verify end-to-end behavior.

testing

9
from vamseeachanta/digitalmodel

Placeholder for testing agents

qa-testing-methodology

9
from jpoutrin/product-forge

QA test design patterns (equivalence partitioning, boundary analysis, accessibility). Auto-loads when designing test cases, planning test coverage, or writing test procedures.