Best for
- Use when the user asks for unit tests (e.
johnqtcg/awesome-skills/skills/unit-test/SKILL.md
Use it for testing and engineering tasks; the detail page covers purpose, installation, and practical steps.
Decision brief
Create and refine Go tests for this repository with table-driven cases and explicit bug-hunting rules.
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/johnqtcg/awesome-skills --skill "skills/unit-test"Inspect the Agent Skill "unit-test" from https://github.com/johnqtcg/awesome-skills/blob/d933bc88237f7a18a7ecf01e5d97a745b083df0f/skills/unit-test/SKILL.md at commit d933bc88237f7a18a7ecf01e5d97a745b083df0f. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
Before writing cases, produce a short Failure Hypothesis List from the target code:
0. Assess target code complexity and select execution mode (Light/Standard/Strict). Declare mode and rationale. 1. Check go.mod for Go version; note version-dependent test pattern adaptations (see Go Version Gate). 2. Exclude generated code files from test scope (see Generated C…
Review the “Quick Reference” section in the pinned source before continuing.
A killer case is a test case designed to catch a specific, named defect. It has four mandatory components:
A killer case is a test case designed to catch a specific, named defect. It has four mandatory components:
Permission review
The documentation asks the agent to create, modify, or delete local files.
Create and refine Go tests for this repository with table-driven cases and explicit bug-hunting rules.The documentation asks the agent to run terminal commands or scripts.
go test -coverprofile=pkg_a.out -covermode=atomic ./pkg/aThe documentation asks the agent to run terminal commands or scripts.
go test -coverprofile=pkg_b.out -covermode=atomic ./pkg/bThe documentation asks the agent to read local files, directories, or repositories.
When present, load repository config from `.unit-test.yaml` (or `.unit-test.json`) before test generation.The documentation asks the agent to read local files, directories, or repositories.
For detailed patterns and Go code examples, load the reference file.Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 94/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 30 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Create and refine Go tests for this repository with table-driven cases and explicit bug-hunting rules.
| When you need to… | Jump to |
|---|---|
| Quick tests for simple functions | Light mode — §Execution Modes |
| Normal feature development | Standard mode (default) — §Execution Modes |
| High-risk / release / concurrent code | Strict mode — §Execution Modes |
| Fix or triage failing tests | §Test Execution Hardening |
| Supplement coverage on existing code | §Coverage Gate Policy |
| Know if a Killer Case is required | Standard + Strict modes: always required — §Killer Case |
| Check Go version compatibility | §Go Version Gate |
| Write a Killer Case | §Killer Case — Definition + load references/killer-case-patterns.md |
<target_file>_test.go, co-located with source.require for fatal preconditions, assert for value checks.t.Fatalf for fatal preconditions, t.Errorf for value checks. Include got/want in messages: t.Errorf("Name = %q, want %q", got, want).cmp.Diff for deep struct comparison. Prefer over field-by-field assertion for complex output._test.go files for "github.com/stretchr/testify" imports. Follow project convention.t.Setenv for env changes; avoid leaking global state between tests. Note: t.Setenv panics under t.Parallel() (see Go Version Gate) — for a parallel subtest that needs env isolation, inject config explicitly instead of mutating the process environment.NewXxx) or private helpers unless explicitly requested OR they contain non-trivial logic (validation/defaulting/option-merging) that can break runtime invariants.go test -race). Scope is the tested package set, not always ./...: PR mode narrows it to changed packages, and a Light pure-function target with no go/chan/sync may run -race on just that package rather than the whole repo. Precedence when the rules below disagree: race.required config > PR scope > mode default. race.required: false disables -race entirely (state it in the report); otherwise -race is required on every tested package.A killer case is a test case designed to catch a specific, named defect. It has four mandatory components:
i < len-1 instead of i < len, dropping the last element")assert/require call that would fail if the defect existsA killer case is NOT just another edge case — it is explicitly tied to a defect hypothesis. If you cannot name the defect it catches, it is not a killer case.
When writing a killer case and you need concrete Go patterns or templates:
→ Load references/killer-case-patterns.md for 6 Go templates covering off-by-one, mapping loss, concurrency, nil-safety, boundary, and error-path defects.
err == nil without verifying the returned valueWhen testing spans multiple packages:
-coverpkg=./... to measure cross-package coverage accurately._test.go files report 0% — exclude them from gate calculations with explicit rationale.coverprofile per package when fine-grained analysis is needed:
go test -coverprofile=pkg_a.out -covermode=atomic ./pkg/a
go test -coverprofile=pkg_b.out -covermode=atomic ./pkg/b
Before generating tests, check go.mod for the project's Go version. Adapt test patterns accordingly:
| Feature | Minimum Go Version | Adaptation |
|---|---|---|
t.Setenv | 1.17 | Below 1.17: use os.Setenv + t.Cleanup. Never call it in a test that (or whose ancestor) calls t.Parallel() — it panics on every Go version, because it mutates process-wide env. This is not version-gated; there is no release where the combination became safe. |
| Range var capture fix | 1.22 | Below 1.22: copy the loop variable (tt := tt) before any t.Run + t.Parallel() closure. On 1.22+ the per-iteration variable makes this redundant. |
t.Chdir | 1.24 | Added in Go 1.24 (below 1.24: os.Chdir + t.Cleanup). Like t.Setenv, it changes process-wide state and cannot be combined with t.Parallel() — it panics if the test has a parallel ancestor. |
If go.mod cannot be read, state the assumption and proceed with Go 1.21 defaults.
go test -shuffle=on to catch tests that depend on execution order. If any test fails only under shuffle, it has hidden state coupling — fix the test, not the ordering.func FuzzXxx), unit tests should cover structured boundary cases that fuzzing is unlikely to find (e.g., specific business rule violations, multi-field interaction). Do not duplicate what fuzzing covers (random byte input, crash discovery). If fuzzing is appropriate but missing, note it in the report as a recommendation.When testing in a CI / PR review context:
BASE="${PR_BASE:-origin/main}" with a merge-base three-dot range. Resolve changed files → package patterns with a ./ prefix: a bare internal/foo is read by go as an import path (package internal/foo is not in std); the ./ prefix makes it a directory.
BASE="${PR_BASE:-origin/main}"
git diff --name-only "$BASE...HEAD" -- '*.go' \
| while IFS= read -r f; do printf './%s\n' "$(dirname "$f")"; done \
| sort -u \
| while IFS= read -r d; do go list "$d" 2>/dev/null; done
Portable (no GNU-only xargs -d, which fails on BSD/macOS xargs); IFS= read -r keeps paths intact; empty diff yields no packages. Assumes gofmt-standard paths (no newlines in filenames).go list resolves forward imports only — there is no flag for "who imports X". Testing changed packages alone can miss a regression in a caller. To include direct dependents, filter go list -f '{{.ImportPath}} {{join .Imports " "}}' ./... for each changed import path. If you skip that, run changed packages only and state explicitly in the report that dependent packages were not covered — do not imply the command above already includes them.go test -race on the resulting package set; the coverage gate applies only to changed packages, not the whole repo._test.go file, flag it as a gap.Discovery uses git, dirname, sort, and go list (all in allowed-tools); the optional dependents step also uses grep. If your tool policy restricts any, run discovery in your shell and pass the package list in.
Do NOT generate tests for files matching these patterns:
*.pb.go (protobuf generated)*_gen.go, wire_gen.go (code generators)mock_*.go, *_mock.go (generated mocks)// Code generated .* DO NOT EDITIf the user explicitly requests testing generated code, proceed but note that generated files are typically validated by their generator's own test suite.
When present, load repository config from .unit-test.yaml (or .unit-test.json) before test generation.
Config keys:
coverage.logic_min: default minimum coverage for logic-heavy packages (default 80)coverage.infra_min: minimum coverage for infra-heavy packages when policy is stricter than default (optional)coverage.package_rules: per-package overrides with explicit rationaleassertion_style: auto|testify|stdlib|go-cmp (prefer auto)race.required: whether -race execution is mandatory in this repo (true|false). Highest precedence — false overrides the default -race requirement (see Hard Rules)commands.test: custom test command templatecommands.coverage: custom coverage command templatemode: auto|light|standard|strict — set the minimum mode floor (default auto). Auto-selection still runs; if it detects a higher mode than the configured floor, the higher mode wins. For example, mode: light allows Light for simple targets but still auto-promotes to Standard/Strict when triggers fire. mode: strict forces Strict for all targets.If config is missing, use this skill's defaults and state: Repository unit-test config not found; using skill defaults.
Select mode before writing tests. Declare the selected mode and rationale at the start of output.
| Criterion | Light | Standard | Strict |
|---|---|---|---|
| Target count | ≤ 3 simple targets | 1-8 targets | > 8 targets (not a standalone trigger — see note) |
| Concurrency | None (no go func, channels, sync.*) | Any | Shared mutable state, error fan-in |
| Dependencies | ≤ 1 failing dependency | Multiple | Complex error chains |
| Branching | ≤ 3 branches per function | Any | Complex state machines |
| Security | Not security-sensitive | Any | Auth, crypto, input sanitization |
| Context usage | Pass-through only | Any | Cancellation/deadline logic |
| Collection transforms | No slice/map transforms (scalar I/O only) | Any | — |
| Invariant patterns | None (trivial arithmetic commutativity like Add(a,b) does not count) | Non-trivial PBT trigger detected (roundtrip, idempotency, preservation, domain-level commutativity, parse validity) | — (use Standard) |
Mode is risk-driven, not count-driven. The Target count row is a signal, not a hard trigger: the actual Strict triggers are the risk rows (concurrency, complex error chains, security, state machines). Ten trivial getters/pure functions do NOT warrant Strict just for crossing > 8 targets — stay at Light/Standard and record the rationale. Promote on risk density (what could break silently), not on how many targets there are.
When in doubt, choose Standard.
| Feature | Light | Standard | Strict |
|---|---|---|---|
| Table-driven tests | Required (2+ cases) | Required (2+ cases) | Required (2+ cases) |
| Mutation-resistant assertions | Required | Required | Required |
Race detection (-race) | Required | Required | Required |
| Coverage gate (80%) | Required | Required | Required |
| Reporting Integrity | Required | Required | Required |
| Case budget per target | 3-6 | 5-12 | 8-15+ |
| Failure Hypothesis List | Skip | Required | Required |
| Killer Case per target | Skip | Required (1) | Required (1+) |
| Removal Risk Statement | Skip | Required | Required |
| Boundary Checklist | Light (5 items) | Full (12 items) | Full (12 items) |
| Scorecard | Light (7 checks) | Full (13 checks) | Full (13 checks) |
| Property-based test guidance | N/A | Recommend if applicable | Required when pattern matches |
| JSON Summary | Skip | Required | Required |
Mark each Covered or N/A:
nil/zero-value input (if parameter type allows)| # | Tier | Check |
|---|---|---|
| L1 | Hygiene | File naming and location correct |
| L2 | Hygiene | Table-driven style used (targets with 2+ cases; single-scenario may be flat) |
| L3 | Critical | Assertions are mutation-resistant (business fields, not existence-only) |
| L4 | Hygiene | Happy path covered |
| L5 | Standard | Critical dependency error paths covered (or N/A) |
| L6 | Standard | -race execution result reported (or N/A with rationale) |
| L7 | Critical | Coverage meets gate (logic >= 80%) |
N/A handling: Standard and Hygiene items marked N/A with explicit rationale count as PASS for tier and total calculations (same rule as the full scorecard). The two Critical items follow the full scorecard's restricted rule: L3 (mutation-resistant assertions) is never N/A; L7 (coverage) is N/A only for cmd/** smoke-tested entry points, generated code, or when coverage genuinely can't run and the exact commands are output.
PASS when: both Critical (L3, L7) PASS (L7 N/A only under the restricted coverage conditions above), Standard >= 1/2, Hygiene >= 2/3, total >= 6/7.
State Light mode: standard scorecard not applicable in output.
Adapt test organization based on the target code type:
| Target Type | Top-level Test Naming | t.Run Organization | Killer Case Granularity |
|---|---|---|---|
| Service interface | TestXxxService | By interface method | 1 per interface method |
| Package-level functions | TestFuncName | By function | 1 per exported function |
| HTTP handler | TestHandlerName | By HTTP method + path | 1 per endpoint |
| CLI command/runner | TestRunnerXxx | By command/subcommand | 1 per command |
| Middleware | TestMiddlewareName | By pass-through / block / error | 1 per middleware |
HTTP handler tests: use httptest.NewRequest + httptest.NewRecorder. Verify status code, response body, headers. Inject dependencies via Deps struct or handler constructor.
Pure function tests: direct table-driven, no mock needed. Focus on input boundaries and output correctness.
Before writing cases, produce a short Failure Hypothesis List from the target code:
i < n, i <= n, i+1, n-1, slice/map access.context.Canceled, DeadlineExceeded, missing ctx propagation, timeout not enforced.Then map each hypothesis to at least one concrete test case name.
Then define at least one killer case per test target and map it to a specific defect hypothesis.
If this mapping is missing, do not proceed to large test generation.
Avoid generating huge suites with weak assertions.
| Mode | Cases per target (typical budget / soft ceiling) | Notes |
|---|---|---|
| Light | 3-6 | Happy path + key error/edge paths |
| Standard | 5-12 | Full budget below + killer case |
| Strict | 8-15+ | Extended budget + property-based tests when applicable |
These ranges are typical budgets and soft ceilings, NOT minimums to pad to. Case count is driven by the target's distinct logic paths, not by the number in the table. If a target has fewer distinct paths than the range's lower bound, stop at the real paths — never manufacture low-value cases (near-duplicate inputs, existence-only assertions) just to reach a minimum. A single-scenario target may legitimately have one case; a sprawling one may exceed the ceiling only when each extra case covers a genuinely distinct path.
Standard/Strict default budget per target:
Only exceed the budget when new cases cover distinct logic paths.
references/bug-finding-techniques.md| # | Technique | Key Rule |
|---|---|---|
| 1 | Mutation-Resistant Assertions | Assert concrete business fields, not just != nil |
| 2 | Collection Mapping Completeness | Assert len + identity + first/middle/last for transforms |
| 3 | Off-by-One Precision | Test n=0,1,2,3 for every index boundary |
| 4 | Dependency Error Propagation | Inject failure per dependency, verify no partial payload |
| 5 | Concurrency & Panic Recovery | Channel barriers, -race, panic recovery path → also see references/concurrency-testing.md |
| 6 | Branch Completeness | Both branches: marker behavior + payload completeness |
| 7 | Killer Case Design | Fault-injection tied to defect hypothesis → also see references/killer-case-patterns.md |
For detailed patterns and Go code examples, load the reference file.
Property-based testing finds bugs that hand-picked boundary cases miss by verifying invariants over randomized input.
| Pattern | Invariant | Example |
|---|---|---|
| Roundtrip | decode(encode(x)) == x | marshal/unmarshal, serialize/deserialize |
| Idempotency | f(f(x)) == f(x) | normalization, canonicalization |
| Preservation | len(output) == len(input) | transforms that must not drop/duplicate items |
| Commutativity | f(a,b) == f(b,a) | set operations, merge functions |
| Parse validity | valid input → no panic | parsers, validators |
testing/quick)func TestRoundtrip(t *testing.T) {
f := func(input string) bool {
decoded, err := Decode(Encode(input))
return err == nil && decoded == input
}
if err := quick.Check(f, nil); err != nil {
t.Error(err)
}
}
For complex domain types, use hand-rolled generators with deterministic seeds. See references/property-based-testing.md.
Relationship to table-driven tests: Property-based tests verify invariants over wide input space; table-driven tests verify exact expected values at specific boundaries. Use both when target has both invariants AND boundary risks.
For Light mode, use the Light Boundary Check (5 items) in Execution Modes.
→ Load references/boundary-scorecard.md for the full 12-item checklist.
t.Run groups map to test targets (interface methods, exported functions, or endpoints).go test -v.t.Parallel() for independent subtests.t.Parallel() when subtests share mutable globals, temp dirs without isolation, or process-wide resources.When the task is fixing failing tests or adding tests to existing code, use these simplified flows instead of the full workflow.
go test -run TestXxx -v -race to verify the fixgo test -coverprofile=before.outgo tool cover -func=before.outgo.mod for Go version; note version-dependent test pattern adaptations (see Go Version Gate).go test ./path/to/pkg -run TestXxx -v -racego test ./path/to/pkg -racego test ./path/to/pkg -coverprofile=coverage.out -covermode=atomic -racego tool cover -func=coverage.out-race or coverage results unless you actually ran the commands and observed output.Score each item PASS / FAIL / N/A (reason). Output Total: X/13 and final result.
Each item has a weight tier that determines its impact on the final verdict:
| Tier | Items | Rule |
|---|---|---|
| Critical (must PASS) | 5, 11, 13 | Any Critical FAIL → overall FAIL regardless of total |
| Standard | 7, 8, 9, 10, 12 | Must achieve >= 4/5 Standard PASS |
| Hygiene | 1, 2, 3, 4, 6 | Must achieve >= 4/5 Hygiene PASS |
Applicability:
Light mode: standard scorecard not applicable.Incremental mode: full scorecard skipped.Incremental + Light mode: minimal scorecard.→ Load references/boundary-scorecard.md for the full 13-item checklist and PASS criteria.
Include:
go.mod) and version-dependent adaptations appliedLight mode output reduction: Skip Failure Hypothesis List, Killer Case list, and JSON Summary. Report only: mode + rationale, targets + case counts, Light Boundary Check, coverage/race results, Light Scorecard, remaining risks.
For list/transform logic, include explicit statement:
Also output a compact JSON block for CI/pipeline ingestion (skip for Light mode):
{
"summary": {
"pass": true,
"score": "12/13",
"go_version": "1.22"
},
"targets": [
{
"name": "TestOrderService",
"type": "Service interface",
"cases": 8,
"killer_cases": 2,
"hypothesis_covered": ["H1", "H3"]
}
],
"coverage": {
"package": "internal/domain/order",
"line_pct": 87.5,
"gate": 80,
"met": true
},
"race": {
"executed": true,
"clean": true
},
"scorecard": {
"critical_pass": 3,
"critical_total": 3,
"standard_pass": 5,
"standard_total": 5,
"hygiene_pass": 4,
"hygiene_total": 5
}
}
Run regression checks for this skill with:
bash "<path-to-skill>/scripts/run_regression.sh"
Frequently asked questions
Create and refine Go tests for this repository with table-driven cases and explicit bug-hunting rules.
The source record exposes this install command: npx skills add https://github.com/johnqtcg/awesome-skills --skill "skills/unit-test". Inspect the command and pinned source before running it.
Static rules flagged write-files, exec-script, read-files in the source; the page lists the matching lines and excerpts.
Alternatives
coreyhaines31/marketingskills
When the user wants to plan, design, or implement an A/B test or experiment, or build a growth experimentation program. Also use when the user mentions "A/B test," "split test," "experiment," "test this change," "variant copy," "multivariate test," "hypothesis," "should I test this," "which version is better," "test two versions," "statistical significance," "how long should I run this test," "growth experiments," "experiment velocity," "experiment backlog," "ICE score," "experimentation program
garrytan/gbrain
End-to-end discipline for turning any large data source (audio libraries, email takeouts, document corpora, chat exports, API dumps) into brain pages at scale. The lifecycle spine: SCHEMA → ACCESS → TRIAL → EVALUATE → IMPROVE → CODIFY → TEST → SKILLIFY → BULK → MONITOR. State is tracked in a durable JSON manifest (see MANIFEST-PATTERN.md) so any crash, session boundary, or subagent fan-out resumes from ground truth instead of memory.
alirezarezvani/claude-skills
App Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklist
dotnet/skills
Migrates .NET test projects from VSTest to Microsoft.Testing.Platform (MTP). Use when user asks to "migrate to MTP", "switch from VSTest", "enable Microsoft.Testing.Platform", "use MTP runner", set OutputType=Exe only for test projects in Directory.Build.props, or mentions EnableMSTestRunner, EnableNUnitRunner, or UseMicrosoftTestingPlatformRunner. USE FOR: MTP behavioral differences vs VSTest (exit code 8, zero tests discovered, --ignore-exit-code, TESTINGPLATFORM_EXITCODE_IGNORE); centralizing