{"id":"1503e047-2b26-4625-a9e4-0ef281fd7a06","shortId":"jBm5fc","kind":"skill","title":"go-testing","tagline":"Use when writing, reviewing, or improving Go test code — including table-driven tests, subtests, parallel tests, test helpers, test doubles, and assertions with cmp.Diff. Also use when a user asks to write a test for a Go function, even if they don't mention specific patterns lik","description":"# Go Testing\n\n## Quick Reference\n\n| Pattern | Use When |\n|---------|----------|\n| `t.Error` | Default — report failure, keep running |\n| `t.Fatal` | Setup failed or continuing is meaningless |\n| `cmp.Diff` | Comparing structs, slices, maps, protos |\n| Table-driven | Many cases share identical logic |\n| Subtests | Need filtering, parallel execution, or naming |\n| `t.Helper()` | Any test helper function (call as first statement) |\n| `t.Cleanup()` | Teardown in helpers instead of defer |\n\n---\n\n## Useful Test Failures\n\n> **Normative**: Test failures must be diagnosable without reading the test\n> source.\n\nEvery failure message must include: function name, inputs, actual (got), and\nexpected (want). Use the format `YourFunc(%v) = %v, want %v`.\n\n```go\n// Good:\nt.Errorf(\"Add(2, 3) = %d, want %d\", got, 5)\n\n// Bad: Missing function name and inputs\nt.Errorf(\"got %d, want %d\", got, 5)\n```\n\nAlways print got before want: `got %v, want %v` — never reversed.\n\n---\n\n## No Assertion Libraries\n\n> **Normative**: Do not use assertion libraries. Use `cmp.Diff` for complex\n> comparisons.\n\n```go\nif diff := cmp.Diff(want, got); diff != \"\" {\n    t.Errorf(\"GetPost() mismatch (-want +got):\\n%s\", diff)\n}\n```\n\nFor protocol buffers, add `protocmp.Transform()` as a cmp option. Always\ninclude the direction key `(-want +got)` in diff messages. Avoid comparing\nJSON/serialized output — compare semantically instead.\n\n> Read [references/TEST-HELPERS.md](references/TEST-HELPERS.md) when writing\n> custom comparison helpers or domain-specific test utilities.\n\n---\n\n## t.Error vs t.Fatal\n\n> **Normative**: Use `t.Error` by default to report all failures in one run.\n> Use `t.Fatal` only when continuing is impossible.\n\n**Choose `t.Fatal` when:**\n- Setup fails (DB connection, file load)\n- The next assertion depends on the previous one succeeding (e.g., decode after\n  encode)\n\n**Never call `t.Fatal`/`t.FailNow` from a goroutine** other than the test\ngoroutine — use `t.Error` instead.\n\n> Read [references/TEST-HELPERS.md](references/TEST-HELPERS.md) when writing\n> helpers that need to choose between t.Error and t.Fatal, or for detailed\n> examples of both.\n\n---\n\n## Table-Driven Tests\n\n> See `assets/table-test-template.go` when scaffolding a new table-driven test and need the canonical struct, loop, and subtest layout.\n\n> **Advisory**: Use table-driven tests when many cases share identical logic.\n\n**Use table tests when:** all cases run the same code path with no conditional\nsetup, mocking, or assertions. A single `shouldErr` bool is acceptable.\n\n**Don't use table tests when:** cases need complex setup, conditional mocking,\nor multiple branches — write separate test functions instead.\n\n**Key rules:**\n- Use field names when cases span many lines or have same-type adjacent fields\n- Include inputs in failure messages — never identify rows by index\n\n> Read [references/TABLE-DRIVEN-TESTS.md](references/TABLE-DRIVEN-TESTS.md)\n> when writing table-driven tests, subtests, or parallel tests.\n\n> **Validation**: After generating or modifying tests, run `go test -run TestXxx -v` to verify the tests compile and pass. Fix any compilation errors before proceeding.\n\n---\n\n## Test Helpers\n\n> **Normative**: Test helpers must call `t.Helper()` first and use `t.Cleanup()`\n> for teardown.\n\n```go\nfunc setupTestDB(t *testing.T) *sql.DB {\n    t.Helper()\n    db, err := sql.Open(\"sqlite3\", \":memory:\")\n    if err != nil {\n        t.Fatalf(\"Could not open database: %v\", err)\n    }\n    t.Cleanup(func() { db.Close() })\n    return db\n}\n```\n\n> Read [references/TEST-HELPERS.md](references/TEST-HELPERS.md) when writing\n> test helpers, cleanup functions, or custom comparison utilities.\n\n---\n\n## Test Error Semantics\n\n> **Advisory**: Test error semantics, not error message strings.\n\n```go\n// Bad: Brittle string comparison\nif err.Error() != \"invalid input\" { ... }\n\n// Good: Semantic check\nif !errors.Is(err, ErrInvalidInput) { ... }\n```\n\nFor simple presence checks when specific semantics don't matter:\n\n```go\nif gotErr := err != nil; gotErr != tt.wantErr {\n    t.Errorf(\"f(%v) error = %v, want error presence = %t\", tt.input, err, tt.wantErr)\n}\n```\n\n---\n\n## Test Organization\n\n> Read [references/TEST-ORGANIZATION.md](references/TEST-ORGANIZATION.md) when\n> working with test doubles, choosing test package placement, or scoping test\n> setup.\n\n> Read [references/VALIDATION-APIS.md](references/VALIDATION-APIS.md) when\n> designing reusable test validation functions.\n\n---\n\n## Integration Testing\n\n> Read [references/INTEGRATION.md](references/INTEGRATION.md) when writing\n> TestMain, acceptance tests, or tests that need real HTTP/RPC transports.\n\n---\n\n## Available Scripts\n\n- **`scripts/gen-table-test.sh`** — Generates a table-driven test scaffold\n\n```bash\nbash scripts/gen-table-test.sh ParseConfig config > config/parse_config_test.go\nbash scripts/gen-table-test.sh --parallel ParseConfig config      # with t.Parallel()\nbash scripts/gen-table-test.sh --output config/parse_config_test.go ParseConfig config\n```\n\n---\n\n## Related Skills\n\n- **Error testing**: See [go-error-handling](../go-error-handling/SKILL.md) when testing error semantics with `errors.Is`/`errors.As` or sentinel errors\n- **Interface mocking**: See [go-interfaces](../go-interfaces/SKILL.md) when creating test doubles by implementing interfaces at the consumer side\n- **Naming test functions**: See [go-naming](../go-naming/SKILL.md) when naming test functions, subtests, or test helper utilities\n- **Linter integration**: See [go-linting](../go-linting/SKILL.md) when running linters alongside tests in CI or pre-commit hooks","tags":["testing","golang","skills","cxuu","agent-skills","ai-agent","ai-assistant","claude","claude-code","codex","cursor","llm"],"capabilities":["skill","source-cxuu","skill-go-testing","topic-agent-skills","topic-ai-agent","topic-ai-assistant","topic-claude","topic-claude-code","topic-codex","topic-cursor","topic-golang","topic-llm"],"categories":["golang-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/cxuu/golang-skills/go-testing","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add cxuu/golang-skills","source_repo":"https://github.com/cxuu/golang-skills","install_from":"skills.sh"}},"qualityScore":"0.491","qualityRationale":"deterministic score 0.49 from registry signals: · indexed on github topic:agent-skills · 82 github stars · SKILL.md body (5,582 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-02T12:55:19.099Z","embedding":null,"createdAt":"2026-04-18T22:13:22.057Z","updatedAt":"2026-05-02T12:55:19.099Z","lastSeenAt":"2026-05-02T12:55:19.099Z","tsv":"'/go-error-handling/skill.md':663 '/go-interfaces/skill.md':680 '/go-linting/skill.md':715 '/go-naming/skill.md':699 '2':148 '3':149 '5':154,167 'accept':385,616 'actual':131 'add':147,211 'adjac':421 'advisori':350,528 'alongsid':719 'also':29 'alway':168,217 'ask':34 'assert':26,180,186,281,379 'assets/table-test-template.go':332 'avail':625 'avoid':227 'bad':155,537 'bash':635,636,641,648 'bool':383 'branch':400 'brittl':538 'buffer':210 'call':98,293,477 'canon':344 'case':82,358,367,392,412 'check':547,555 'choos':270,316,591 'ci':722 'cleanup':519 'cmp':215 'cmp.diff':28,72,189,196 'code':12,371 'commit':726 'compar':73,228,231 'comparison':192,240,523,540 'compil':462,467 'complex':191,394 'condit':375,396 'config':639,645,653 'config/parse_config_test.go':640,651 'connect':276 'consum':690 'continu':69,267 'could':501 'creat':682 'custom':239,522 'd':150,152,163,165 'databas':504 'db':275,492,511 'db.close':509 'decod':289 'default':60,255 'defer':108 'depend':282 'design':603 'detail':323 'diagnos':117 'diff':195,199,207,225 'direct':220 'domain':244 'domain-specif':243 'doubl':24,590,684 'driven':16,80,329,339,354,440,632 'e.g':288 'encod':291 'err':493,498,506,550,565,579 'err.error':542 'errinvalidinput':551 'error':468,526,530,533,572,575,656,661,666,673 'errors.as':670 'errors.is':549,669 'even':43 'everi':123 'exampl':324 'execut':90 'expect':134 'f':570 'fail':67,274 'failur':62,111,114,124,259,426 'field':409,422 'file':277 'filter':88 'first':100,479 'fix':465 'format':138 'func':486,508 'function':42,97,128,157,404,520,607,694,703 'generat':448,628 'getpost':201 'go':2,10,41,52,144,193,453,485,536,562,660,678,697,713 'go-error-handl':659 'go-interfac':677 'go-lint':712 'go-nam':696 'go-test':1 'good':145,545 'goroutin':298,303 'got':132,153,162,166,170,173,198,204,223 'goterr':564,567 'handl':662 'helper':22,96,105,241,312,472,475,518,707 'hook':727 'http/rpc':623 'ident':84,360 'identifi':429 'implement':686 'imposs':269 'improv':9 'includ':13,127,218,423 'index':432 'input':130,160,424,544 'instead':106,233,306,405 'integr':608,710 'interfac':674,679,687 'invalid':543 'json/serialized':229 'keep':63 'key':221,406 'layout':349 'librari':181,187 'lik':51 'line':415 'lint':714 'linter':709,718 'load':278 'logic':85,361 'loop':346 'mani':81,357,414 'map':76 'matter':561 'meaningless':71 'memori':496 'mention':48 'messag':125,226,427,534 'mismatch':202 'miss':156 'mock':377,397,675 'modifi':450 'multipl':399 'must':115,126,476 'n':205 'name':92,129,158,410,692,698,701 'need':87,314,342,393,621 'never':177,292,428 'new':336 'next':280 'nil':499,566 'normat':112,182,251,473 'one':261,286 'open':503 'option':216 'organ':582 'output':230,650 'packag':593 'parallel':19,89,444,643 'parseconfig':638,644,652 'pass':464 'path':372 'pattern':50,56 'placement':594 'pre':725 'pre-commit':724 'presenc':554,576 'previous':285 'print':169 'proceed':470 'proto':77 'protocmp.transform':212 'protocol':209 'quick':54 'read':119,234,307,433,512,583,599,610 'real':622 'refer':55 'references/integration.md':611,612 'references/table-driven-tests.md':434,435 'references/test-helpers.md':235,236,308,309,513,514 'references/test-organization.md':584,585 'references/validation-apis.md':600,601 'relat':654 'report':61,257 'return':510 'reusabl':604 'revers':178 'review':7 'row':430 'rule':407 'run':64,262,368,452,455,717 'same-typ':418 'scaffold':334,634 'scope':596 'script':626 'scripts/gen-table-test.sh':627,637,642,649 'see':331,658,676,695,711 'semant':232,527,531,546,558,667 'sentinel':672 'separ':402 'setup':66,273,376,395,598 'setuptestdb':487 'share':83,359 'shoulderr':382 'side':691 'simpl':553 'singl':381 'skill':655 'skill-go-testing' 'slice':75 'sourc':122 'source-cxuu' 'span':413 'specif':49,245,557 'sql.db':490 'sql.open':494 'sqlite3':495 'statement':101 'string':535,539 'struct':74,345 'subtest':18,86,348,442,704 'succeed':287 't.cleanup':102,482,507 't.error':59,248,253,305,318 't.errorf':146,161,200,569 't.failnow':295 't.fatal':65,250,264,271,294,320 't.fatalf':500 't.helper':93,478,491 't.parallel':647 'tabl':15,79,328,338,353,363,389,439,631 'table-driven':14,78,327,337,352,438,630 'teardown':103,484 'test':3,11,17,20,21,23,38,53,95,110,113,121,246,302,330,340,355,364,390,403,441,445,451,454,461,471,474,517,525,529,581,589,592,597,605,609,617,619,633,657,665,683,693,702,706,720 'testing.t':489 'testmain':615 'testxxx':456 'topic-agent-skills' 'topic-ai-agent' 'topic-ai-assistant' 'topic-claude' 'topic-claude-code' 'topic-codex' 'topic-cursor' 'topic-golang' 'topic-llm' 'transport':624 'tt.input':578 'tt.wanterr':568,580 'type':420 'use':4,30,57,109,136,185,188,252,263,304,351,362,388,408,481 'user':33 'util':247,524,708 'v':140,141,143,174,176,457,505,571,573 'valid':446,606 'verifi':459 'vs':249 'want':135,142,151,164,172,175,197,203,222,574 'without':118 'work':587 'write':6,36,238,311,401,437,516,614 'yourfunc':139","prices":[{"id":"a9ee8874-2b96-4819-85df-c80671738ce6","listingId":"1503e047-2b26-4625-a9e4-0ef281fd7a06","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"cxuu","category":"golang-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T22:13:22.057Z"}],"sources":[{"listingId":"1503e047-2b26-4625-a9e4-0ef281fd7a06","source":"github","sourceId":"cxuu/golang-skills/go-testing","sourceUrl":"https://github.com/cxuu/golang-skills/tree/main/skills/go-testing","isPrimary":false,"firstSeenAt":"2026-04-18T22:13:22.057Z","lastSeenAt":"2026-05-02T12:55:19.099Z"}],"details":{"listingId":"1503e047-2b26-4625-a9e4-0ef281fd7a06","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"cxuu","slug":"go-testing","github":{"repo":"cxuu/golang-skills","stars":82,"topics":["agent-skills","ai-agent","ai-assistant","claude","claude-code","codex","cursor","go","golang","llm"],"license":"apache-2.0","html_url":"https://github.com/cxuu/golang-skills","pushed_at":"2026-03-15T19:32:10Z","description":"AI Agent Skills for idiomatic, production-ready Go code, distilled from Google, Uber, Community","skill_md_sha":"0d487dd829970004372ebe3825b08662c63acc93","skill_md_path":"skills/go-testing/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/cxuu/golang-skills/tree/main/skills/go-testing"},"layout":"multi","source":"github","category":"golang-skills","frontmatter":{"name":"go-testing","license":"Apache-2.0","description":"Use when writing, reviewing, or improving Go test code — including table-driven tests, subtests, parallel tests, test helpers, test doubles, and assertions with cmp.Diff. Also use when a user asks to write a test for a Go function, even if they don't mention specific patterns like table-driven tests or subtests. Does not cover benchmark performance testing (see go-performance).","compatibility":"Uses github.com/google/go-cmp for cmp.Diff comparisons"},"skills_sh_url":"https://skills.sh/cxuu/golang-skills/go-testing"},"updatedAt":"2026-05-02T12:55:19.099Z"}}