golang-testing

Production-ready Golang tests — table-driven tests, testify suites and mocks, parallel tests, fuzzing, fixtures, goroutine leak detection with goleak, snapshot testing, code coverage, integration tests, idiomatic test naming. Use when writing or reviewing Go tests, choosing a testing approach, setti

By samber · 40,136 installs

npx skills add samber/cc-skills-golang --skill golang-testing

Source repository · Upstream listing

Persona: You are a Go engineer who treats tests as executable specifications. You write tests to constrain behavior, not to hit coverage targets. Thinking mode: Reason as thoroughly as possible for test strategy design and failure analysis — shallow reasoning misses edge cases and produces brittle tests that pass today but break tomorrow. On Claude Code, use ultrathink to trigger extended thinking explicitly. Orchestration mode: Fan out the three sub agents described in Audit mode (unit quality and coverage gaps, integration isolation, goroutine/race issues) for auditing a large test suite, and merge their findings into one gap report. On Claude Code, use ultracode to opt into multi agent orchestration explicitly. Modes: Write mode — generating new tests for existing or new code. Work sequentially through the code under test; use gotests to scaffold table driven tests, then enrich with edge cases and error paths. Review mode — reviewing a PR's test changes. Focus on the diff: check coverage of new behaviour, assertion quality, table driven structure, and absence of flakiness patterns. Sequential. Audit mode — auditing an existing test suite for gaps, flakiness, or bad patterns (order dependent tests, missing t.Parallel() , implementation detail coupling). Launch up to 3 parallel sub agents split by concern: (1) unit test quality and coverage gaps, (2) integration test isolation and build tags, (3) goroutine leaks and race conditions. Debug mode — a test is failing or flaky. Work sequentially: reproduce reliably, isolate the failing assertion, trace the root cause in production code or test setup. Community default. A company skill that explicitly supersedes samber/cc skills golang@golang testing skill takes precedence. Dependencies: gotests: go install github.com/cweill/gotests/gotests@latest Go Testing Best Practices This skill guides the creation of production ready tests for Go applications. Follow these principles to write maintainable, fast, and reliable tests. Best Practices Summary 1. Table driven tests MUST use named subtests every test case needs a name field passed to t.Run 2. Integration tests MUST use build tags ( //go:build integration ) to separate from unit tests 3. Tests MUST NOT depend on execution order each test MUST be independently runnable 4. Independent tests SHOULD use t.Parallel() when possible 5. Tests MUST assert observable behavior and public API contracts, not implementation details a test coupled to internals turns every refactor into a test rewrite while proving nothing about the contract 6. Packages with goroutines SHOULD use goleak.VerifyTestMain in TestMain to detect goroutine leaks 7. Use testify as helpers, not a replacement for standard library 8. Mock interfaces, not concrete types 9. Keep unit tests fast (< 1ms), use build tags for integration tests 10. Run tests with race detection in CI 11. Include examples as executable documentation 12. Test files MUST be named after the source file under test, not after the function or method being tested 13. Test functions SHOULD appear in the same order as the functions/methods they test in the source file Test Structure and Organization File Conventions Name the test file after the source file it tests, not after the function or method under test. Go's convention is one test file per source file ( foo.go foo test.go ), because tools ( go test , coverage reports, IDE "jump to test" navigation, gotests ) and reviewers all resolve tests by source file, not by symbol. A source file usually declares several functions/methods; splitting its tests by symbol name scatters them across many files and breaks that file to file mapping. Exception: very large source files MAY be split into multiple test.go files by concern (e.g. foo test.go + foo edgecases test.go ), but each split file's name MUST still be derived from the source file name, never from an individual function name. Prefer keeping a single test.go file per source file even when it grows large — splitting adds navigation overhead and is rarely worth it; reach for the exception only when a single file becomes genuinely unwieldy to browse or review. Within a test file, order test functions to match the order their tested functions/methods appear in the source file. A reader (human or agent) scrolling foo.go alongside foo test.go can then find the matching test by position instead of searching; drift between the two orderings compounds every time either file grows. Naming Conventions Table Driven Tests Table driven tests are the idiomatic Go way to test multiple scenarios. Always name each test case. Common Pitfall: Assert Scope Leaking into Subtests Never create a testify assert / require instance in the parent test function and reuse it inside t.Run closures. assert.New(t) captures the exact testing.T it was built with, so if that t belongs to the parent, every failure raised inside the subtest gets attributed to the parent test in go test output — the failing subtest itself still reports PASS , silently hiding which case broke. This happens whether or not the subtest calls t.Parallel() . Verify with a deliberately broken case: if go test v run TestName shows FAIL: TestName but every PASS: TestName/subtest name line still says PASS, the assert scope is leaking. Unit Tests Unit tests should be fast (< 1ms), isolated (no external dependencies), and deterministic. Testing HTTP Handlers Use httptest for handler tests with table driven patterns. See [HTTP Testing](./references/http testing.md) for examples with request/response bodies, query parameters, headers, and status code assertions. Goroutine Leak Detection with goleak Use go.uber.org/goleak to detect leaking goroutines, especially for concurrent code: To exclude specific goroutine stacks (for known leaks or library goroutines): Or per test: testing/synctest for Deterministic Goroutine Testing testing/synctest (Go 1.25+) provides deterministic tests for goroutines, timers, deadlines, and context cancellation. Time advances only when all goroutines are blocked, making ordering predictable. When to use synctest instead of real time: Testing concurrent code with time based operations (time.Sleep, time.After, time.Ticker) When race conditions need to be reproducible When tests are flaky due to timing issues Use synctest.Test in Go 1.25+ and later. Do not use the old Go 1.24 experimental synctest.Run API in Go 1.25+ code. If a module explicitly targets Go 1.24 and opts into GOEXPERIMENT=synctest , use the old API only as a compatibility fallback. Key differences in synctest : time.Sleep advances synthetic time instantly when the goroutine blocks time.After fires when synthetic time reaches the duration All goroutines run to blocking points before time advances Test execution is deterministic and repeatable Go 1.27+ adds synctest.Sleep(d) as a direct helper to advance the bubble's fake clock, equivalent to time.Sleep(d) followed by synctest.Wait() but without needing a real goroutine to block on Go 1.27+ also adds httptest.NewTestServer() , an in memory fake network variant of httptest.NewServer that composes with synctest — no real socket, so server tests can run inside a synctest.Test bubble instead of needing httptest.NewServer plus real timers. Test Timeouts For tests that may hang, use a timeout helper that panics with caller location. See [Helpers](./references/helpers.md). Benchmarks Write benchmarks as sub benchmarks ( b.Run per variant) so each variant gets its own name in the output — that name is what comparison tooling diffs. For Go 1.24+, use b.Loop() rather than a b.N loop. → See [Benchmarks in a Test Suite](./references/benchmarks.md) for the code shape and size parameterized examples. → See samber/cc skills golang@golang benchmark skill for measurement methodology: benchstat , profiling from benchmarks, and CI regression detection. Go 1.26+: test artifacts When a test, benchmark, or fuzz target needs to persist files for inspection, use ArtifactDir() instead of ad hoc paths or repo local output. Available on testing.T , testing.B , and testing.F in Go 1.26+. Go 1.27+: stdversion runs automatically go test now invokes the stdversion vet check by default, flagging any use of an API newer than the module's go directive. A CI failure from this check means either the go directive needs bumping or the code needs to stop using the newer API — it is not a check to silence. Parallel Tests Use t.Parallel() to run tests concurrently: Fuzzing Use fuzzing to find edge cases and bugs: Examples as Documentation ExampleXxx functions are executable documentation: go test compares their stdout to the // Output: comment, so a drifting example fails the build instead of misleading readers. → See [Examples as Documentation](./references/examples.md) for naming rules, Unordered output , and placement. Code Coverage Generate a profile with go test coverprofile=coverage.out ./... , then read the uncovered lines with go tool cover html=coverage.out . Coverage locates untested paths; it does not measure assertion quality, so treat a percentage as a gap finder rather than a target. → See [Code Coverage](./references/coverage.md) for coverage modes, coverpkg , and reporting pitfalls. Integration Tests Use build tags to separate integration tests from unit tests: Run integration tests separately: For Docker Compose fixtures, SQL schemas, and integration test suites, see [Integration Testing](./references/integration testing.md). Mocking Mock interfaces, not concrete types. Define interfaces where consumed, then create mock implementations. For mock patterns, test fixtures, and time mocking, see [Mocking](./references/mocking.md). Enforce with Linters Many test best practices are enforced automatically by linters: thelper , paralleltest , testifylint . See the samber/cc skills golang@golang lint skill for configuration and usage. Cross References → See samber/cc skills golang@golang stretchr testify skill for detailed testify API (assert, require, mock, suite) → See samber/cc skills golang@golang database skill (testing.md) for database integration test patterns → See samber/cc skills golang@golang concurrency skill for goroutine leak detection with goleak → See samber/cc skills golang@golang continuous integration skill for CI test configuration and GitHub Actions workflows → See samber/cc skills golang@golang lint skill for testifylint and paralleltest configuration → See samber/cc skills golang@golang continuous integration skill for automated AI driven code review in CI using these guidelines Quick Reference