agentleFS
alexderzalexderz/agentic-toolbox/skills/golang-testing/SKILL.md

golang-testing

Skill5 starsChanged 46 days agoMITView on GitHub

use this when writing, reviewing, or debugging Go tests — table-driven named subtests, t.Parallel, goleak, synctest, fuzz, build-tagged integration, race, and idiomatic file naming.

  • Installs packages

51 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use golang-error-handling, golang-concurrency and 8 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • tquangkhai98Skill

    golang-error-handling

    Idiomatic Golang error handling — creation, wrapping with %w, errors.Is/As, errors.Join, custom error types, sentinel errors, panic/recover, the single handling rule, structured logging with slog, HTTP request logging middleware, and samber/oops for production errors. Built to make logs usable at scale with log aggregation 3rd-party tools. Apply when creating, wrapping, inspecting, or logging errors in Go code.

    Also in 14 projects that use this

  • tquangkhai98Skill

    golang-concurrency

    Golang concurrency patterns. Use when writing or reviewing concurrent Go code involving goroutines, channels, select, locks, sync primitives, errgroup, singleflight, worker pools, or fan-out/fan-in pipelines. Also triggers when you detect goroutine leaks, race conditions, channel ownership issues, or need to choose between channels and mutexes.

    Also in 14 projects that use this

  • alexastrumSkill

    golang-how-to

    Golang skills orchestrator — always active on any Golang coding, review, debug, or setup task. Reads the task context and loads the most relevant skills from samber/cc-skills-golang, often multiple at once: writing a gRPC service loads golang-grpc + golang-testing + golang-error-handling; debugging a panic loads golang-troubleshooting + golang-safety; auditing security loads golang-security + golang-lint + golang-safety. Also: disambiguates competing clusters when two skills seem to overlap (performance vs benchmark vs troubleshooting, samber/lo vs mo vs ro, DI cluster, safety vs security), and configures CLAUDE.md or AGENTS.md to force-trigger skills in a project (/golang-how-to configure).

    Also in 7 projects that use this

  • guynhsichngeodiecSkill

    golang-context

    Idiomatic context.Context usage in Golang — creation, propagation, cancellation, timeouts, deadlines, context values, and cross-service tracing. Apply when working with context.Context in any Go code.

    Also in 11 projects that use this

  • guynhsichngeodiecSkill

    golang-samber-lo

    Functional programming helpers for Golang using samber/lo — 500+ type-safe generic functions for slices, maps, channels, strings, math, tuples, and concurrency (Map, Filter, Reduce, GroupBy, Chunk, Flatten, Find, Uniq, etc.). Core immutable package (lo), concurrent variants (lo/parallel aka lop), in-place mutations (lo/mutable aka lom), lazy iterators (lo/it aka loi for Go 1.23+), and experimental SIMD (lo/exp/simd). Apply when using or adopting samber/lo, when the codebase imports github.com/samber/lo, or when implementing functional-style data transformations in Go. Not for streaming pipelines (→ See golang-samber-ro skill).

    Also in 9 projects that use this

  • +5 more from tquangkhai98

The file

We split this skill into the rules it gives an agent

2 rules. 0 are common, 2 are distinctive, and 0 are very specific to this project.

  • 0

    Common

    Most of the 47 edited versions we read keep these.

  • 2

    Distinctive

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Do not self-except. Record the choice.

    line 46
  2. Distinctive:

    Stop. Name the case. Assert the contract.

    line 180

“Common” is measured: kept by at least 6 in 10 of the 47 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Go testing

Process skills that may load with this one: load-with list.

Iron law

Tests constrain observable behavior, not coverage percentages.

Each case is independently runnable, named, and attributed to its own *testing.T. Coverage is a gap finder. A green percentage with weak assertions is theater.

Always

RuleWhy
Table-driven cases with a name passed to t.Rungo test -run Test/case and failure output need the name
One _test.go per source file (foo.go → foo_test.go)Tools and reviewers resolve by file, not by symbol
Order tests like the source functionsDrift makes the pair unreadable
Assert the public contractInternals-coupled tests rewrite on every refactor and prove nothing
Independently runnable casesOrder dependence is a flake factory
t.Parallel() on independent testsDefault-serial is leftover time
Build-tag integration (//go:build integration)Unit go test ./... stays fast and hermetic
go test -race in CIData races do not show up as assertion failures
goleak.VerifyTestMain when the package starts goroutinesLeaks are silent until production
Mock interfaces defined at the consumerConcrete mocks lock the wrong type
testify as helpers on top of testingIt is not a replacement for the stdlib
ExampleXxx with // Output: for public APIDrifting docs fail the build
Fresh go test evidence before claiming greenverify-before-done

Ask first

TopicWhy it is a stop
White-box (package foo) vs black-box (package foo_test)Unexported access is a design choice, not a default
Skipping t.Parallel() on a large independent suiteSay why (shared mutable fixture, global env)
Adding testify / mock codegen the module does not already useNew test dep is a project dep
go install github.com/cweill/gotests/gotests@latestUnpinned installer; INTAKE: no skill scripts
Integration tests without a build tagThey hitch a ride on every unit run
Ignoring known goroutines in goleakIgnoreCurrent hides leaks — name them
Coverage gates as a merge targetPercentage ≠ assertion quality

Do not self-except. Record the choice.

Never

NeverWhy
Parent assert.New(t) / require.New(t) reused inside t.RunFailures attach to the parent; the subtest still prints PASS
Tests that only pass in a fixed orderHidden shared state
Mocking a concrete typeYou tested the mock, not the consumer
Sleep-based synchronization as the flake fixUse synctest (Go 1.25+) or a real sync point
synctest.Run in Go 1.25+ codeThat API is the 1.24 experiment; use synctest.Test
Silencing stdversion (Go 1.27+ default vet)Bump the go directive or stop using the newer API
Writing artifacts into the repo from a testGo 1.26+ t.ArtifactDir() (also B / F)
Installing the samber pack or clawhubDual routers; security CLEAR is SKILL-only
Copying evals/, EVALUATIONS.md, clawhub-publish.sh, or scripts/Quarantined by intake

Modes (one pass)

ModeDo
WriteOne behavior at a time. Table + named t.Run. Edges and error paths. tdd still applies.
ReviewDiff only: new behavior covered, assertions on the contract, no flake patterns, no assert-scope leak.
AuditThree concerns, then one report: (1) unit quality / gaps, (2) integration isolation / tags, (3) leaks / races.
DebugReproduce, isolate the assertion, then the production or setup cause. Do not “fix” a flake with sleep.

Shape

func TestAdd(t *testing.T) {}                 // function
func TestMyStruct_MyMethod(t *testing.T) {}   // method
func BenchmarkAdd(b *testing.B) {}            // benchmark: b.Run per variant; Go 1.24+ b.Loop()
func ExampleAdd() {}                          // example
func FuzzAdd(f *testing.F) {}                 // fuzz

Same-package tests see unexported names. package foo_test sees the public API only. Prefer black-box unless you are testing a package invariant that is not exported.

Split foo_test.go / foo_edgecases_test.go only when one file is genuinely unwieldy — still named from the source file, never from a single function.

Table-driven

func TestCalculatePrice(t *testing.T) {
    tests := []struct {
        name      string
        quantity  int
        unitPrice float64
        want      float64
    }{
        {name: "single item", quantity: 1, unitPrice: 10, want: 10},
        {name: "zero quantity", quantity: 0, unitPrice: 10, want: 0},
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got := CalculatePrice(tt.quantity, tt.unitPrice)
            if got != tt.want {
                t.Fatalf("CalculatePrice(%d, %.2f) = %.2f, want %.2f",
                    tt.quantity, tt.unitPrice, got, tt.want)
            }
        })
    }
}

stdlib t.Fatalf is enough. If you use testify, build assert.New(t) inside the subtest from that subtest’s t. Probe a broken case: parent FAIL + every --- PASS: Test/case means the assert leaked.

t.Parallel() goes on the subtest (and the parent if the parent has no shared setup). Build the assert after t.Parallel(), from the subtest t.

Integration

//go:build integration

func TestDatabaseIntegration(t *testing.T) { /* real store */ }
go test -tags=integration ./...

Unit tests: fast, no network, no live store. HTTP handlers: net/http/httptest. Go 1.27+ httptest.NewTestServer is the in-memory server that composes with synctest.

Leaks and time

Packages that start goroutines:

func TestMain(m *testing.M) { goleak.VerifyTestMain(m) }

Per-test: defer goleak.VerifyNone(t).

Go 1.25+ testing/synctest: synctest.Test(t, func(t *testing.T) { ... }). Fake time advances when every goroutine in the bubble is blocked — use it for Sleep / After / Ticker / deadlines instead of wall-clock flakes. Go 1.27+ synctest.Sleep(d) advances the bubble clock directly.

Fuzz and examples

Seed with f.Add, then assert an invariant (round-trip, parse/format). ExampleXxx stdout must match // Output:.

Coverage: go test -coverprofile=coverage.out ./... then go tool cover -html=coverage.out. Read uncovered lines. Do not treat the number as DoD.

Linters that catch this skill’s rules: thelper, paralleltest, testifylint. tester owns hook wiring — do not remint CI here.

Commands

go test ./...                     # unit (no integration tag)
go test -race ./...               # CI default for concurrent packages
go test -run TestName/case ./...  # one named case
go test -count=1 ./...            # no cache when proving a claim
go test -tags=integration ./...
go test -fuzz=FuzzName ./...
go test -bench=. -benchmem ./...

Roles

RoleOwnsDoes not own
builderThis skill; Go test shape in product reposInstalling the samber pack
testergofmt / race / lint hooks when .go appearsClaiming product DoD from fmt-only green
securityIntake; CLEAR conditions (SKILL only)Day-to-day testify coaching
managerAfter-act landed+verifiedBlessing a suite that skipped tdd / verify

Workers do not bypass security: Roles. A green go test is not a security clear of this skill home.

Red flags

  • “I’ll assert the mock was called and call it covered”
  • “Share one assert across the table — cleaner”
  • “It only fails under -count=1 / -race / -shuffle=on, so ignore it”
  • “Sleep(10ms) makes it stable”
  • “Install gotests / the samber pack to write Go tests”
  • “Copy evals or clawhub so we can score the skill”

Stop. Name the case. Assert the contract. Run fresh evidence.

Upstream pin

samber/cc-skills-golang skills/golang-testing @ 22c58a55a0a799b901aa251172923180bad9e010 (MIT). Body is a compress of SKILL.md only. See SOURCES.md.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.