hunter-party-go/test-hunter-go/SKILL.md
Audit Go test code for quality gaps — missing coverage on critical paths, brittle tests coupled to implementation, over-mocking, assertion-free tests, missing edge cases, table-driven test misuse, and race condition blindness. Focuses on test effectiveness. Use when: reviewing Go test suites for reliability, reducing false-positive test failures, improving coverage of critical business logic, or cleaning up test debt.
npx skillsauth add skyosev/agent-skills test-hunter-goInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Audit test code for quality and coverage gaps — tests that verify implementation details instead of behavior, interface-based test doubles so elaborate that nothing real is tested, critical paths with no coverage, and duplicated setup that makes the suite fragile. The goal: tests catch real bugs, survive refactors, and cover the paths that matter most.
Test behavior, not implementation. A test should verify what the code does, not how it does it. If renaming an internal function or reordering private methods breaks a test, the test is coupled to implementation — it will fail on safe refactors and pass on real bugs.
Coverage is not confidence. High line coverage with shallow assertions is worse than focused coverage with meaningful assertions on critical paths. Prioritize coverage of business logic, error handling, and edge cases over hitting every line.
Prefer real collaborators over test doubles. Interface-based test doubles are idiomatic in Go, but each one is a place where the test diverges from reality. Favor real implementations where possible; use test doubles for external boundaries (network, filesystem, clock), not internal packages. If a unit test requires 5+ injected test doubles to run, the unit under test has too many dependencies or the test is too isolated.
Tests are code. They deserve the same quality standards as production code — no duplication, clear naming, and readable assertions. A test that requires reading the source to understand what it verifies is a bad test.
Edge cases are where bugs hide. Empty input, nil, zero, negative numbers, maximum values, Unicode, concurrent access, context cancellation — these are the inputs developers forget and users provide.
Table-driven tests are a tool, not a mandate. Use them when there are genuinely multiple inputs to the same logic. A table-driven test with one entry or with entries that exercise fundamentally different code paths is misused.
Race detection is non-negotiable. Go code handling concurrency must be tested with -race. Tests that pass
without -race but fail with it are hiding real bugs.
Business logic, error handling, and security-sensitive code with no test coverage.
Signals:
_test.go filesAction: Flag the critical path and its risk level. Recommend specific test cases for the highest-risk gaps.
Tests that break on safe refactors because they depend on internal details.
Signals:
reflect or unsafeerrors.Is/errors.AsAction: Rewrite to assert on observable outputs: return values, side effects at boundaries (HTTP responses, DB state, emitted events), or user-visible behavior.
Tests where so much is replaced with test doubles that the test verifies wiring, not logic.
Signals:
Action: Remove test doubles on internal packages. Mock only external boundaries (network, filesystem, clock, randomness). If the unit requires many doubles, consider testing at a higher integration level.
Tests that execute code but never verify meaningful outcomes.
Signals:
t.Error, t.Fatal, assertion library calls, or comparison checksif err != nil with no check on the actual resulterr == nil but ignore the returned value entirelyt.Log() used as a substitute for assertions (printing results instead of checking them)err != nil without checking the error type or messageAction: Add specific assertions on return values, state changes, or side effects. Every test should answer "what would break if this code had a bug?"
Tests that cover the happy path but miss boundary conditions, error cases, and unusual inputs.
Signals:
Action: Flag the specific edge cases missing for each function/package. Prioritize by risk: error paths and boundary conditions in core logic first.
Table-driven tests that are poorly structured, have single entries, or mix unrelated test scenarios.
Signals:
t.Run() with named subtests (failures don't identify which case failed)name field or with unhelpful names like "test1", "test2"Action: Split unrelated cases into separate tests. Add t.Run() with descriptive names. Remove single-entry tables.
Repeated setup, shared fixtures, and copied test blocks that make the suite fragile and hard to maintain.
Signals:
var in test files that creates shared mutable state between testsTestMain() that sets up state used across unrelated testsAction: Extract shared setup into focused test helper functions marked with t.Helper(). Parameterize repeated
test cases with table-driven tests. Eliminate shared mutable state between tests.
Patterns that cause tests to pass or fail non-deterministically.
Signals:
time.Sleep in tests (timing-dependent)time.Now() or random values without seedingt.TempDir() cleanup-race flagAction: Replace timing waits with channel-based synchronization or polling. Inject clocks and random sources. Use
t.TempDir() for filesystem tests. Run all concurrent tests with -race.
main/master)BASE=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@' || echo main)
SCOPE=$(git diff --name-only $(git merge-base HEAD $BASE)...HEAD)
Constrain all subsequent scans to the resolved surface.testing package, testify, gocheck, or other assertion
libraries. Note if the project uses gomock, mockery, or hand-rolled test doubles.# Test files
rg -l 'func Test' --type go --glob '*_test.go'
# Assertion-free tests (test functions without error/fatal/assert calls)
rg -U 'func Test\w+\(t \*testing\.T\)\s*\{[^}]*\}' --type go --glob '*_test.go'
# Test double density (count interface/mock declarations per test file)
rg -c '(mock|Mock|fake|Fake|stub|Stub)' --type go --glob '*_test.go' --sort path
# Table-driven tests
rg 'tests? :?= \[\]struct|cases :?= \[\]struct|tt\.name|tc\.name' --type go --glob '*_test.go'
# Timing-dependent patterns
rg 'time\.Sleep|time\.After' --type go --glob '*_test.go'
# Shared mutable state in tests
rg '^\s*var\s+\w+' --type go --glob '*_test.go'
# Missing t.Helper() in test helpers
rg 'func\s+\w+\(t \*testing\.(T|B)' --type go --glob '*_test.go'
# Missing t.Run for subtests
rg 'for.*range.*tests|for.*range.*cases' --type go --glob '*_test.go'
# Coverage gaps: source files without corresponding test files
# (compare .go file list to _test.go file list — project-specific)
# Race-sensitive patterns
rg 'go\s+func|go\s+\w+\(' --type go --glob '*_test.go'
_test.go file exist? Does it cover error paths and edge cases?For each test file:
t.Run()?Save as YYYY-MM-DD-test-hunter-audit-{$LLM-name}.md in the project's docs folder (or project root if no docs folder exists).
# Test Hunter Audit — {date}
## Scope
- Surface: {diff / path / codebase}
- Files: {count or list}
- Test framework: {standard testing / testify / gocheck / etc.}
- Mocking approach: {hand-rolled / gomock / mockery / none}
- Exclusions: {list}
## Coverage Gaps
| # | Package | Location | Risk | Test File | Action |
| - | ------- | -------- | ---- | --------- | ------ |
| 1 | payment | file:line | High | None | Add tests for charge, refund, and failure paths |
## Findings
### Brittle Tests
| # | Test | Location | Coupling | Action |
| - | ---- | -------- | -------- | ------ |
| 1 | TestProcessOrder | file:line | Asserts mock called 3 times | Assert on returned order state |
### Over-Mocking
| # | Test File | Location | Doubles | Assertions | Action |
| - | --------- | -------- | ------- | ---------- | ------ |
| 1 | user_test.go | file:line | 8 interfaces | 2 assertions | Remove internal mocks, test at integration level |
### Assertion-Free / Weak Assertions
| # | Test | Location | Issue | Action |
| - | ---- | -------- | ----- | ------ |
| 1 | TestCreateUser | file:line | Only checks `err == nil` | Assert on specific user fields |
### Missing Edge Cases
| # | Package | Location | Missing Cases | Action |
| - | ------- | -------- | ------------- | ------ |
| 1 | `ValidateEmail()` | file:line | Empty string, Unicode, max length | Add boundary tests |
### Table-Driven Test Issues
| # | Test | Location | Issue | Action |
| - | ---- | -------- | ----- | ------ |
| 1 | TestParse | file:line | Single-entry table | Convert to regular test |
### Test Duplication
| # | Pattern | Locations | Action |
| - | ------- | --------- | ------ |
| 1 | Identical user factory in 5 files | file:line, file:line, ... | Extract shared test helper with t.Helper() |
### Flaky Test Indicators
| # | Test | Location | Pattern | Action |
| - | ---- | -------- | ------- | ------ |
| 1 | TestTimeout | file:line | `time.Sleep(1 * time.Second)` | Use channel synchronization |
## Recommendations (Priority Order)
1. **Must-fix**: {missing coverage on critical paths, assertion-free tests, flaky indicators, missing -race testing}
2. **Should-fix**: {brittle tests, over-mocking, missing edge cases}
3. **Consider**: {test duplication, table-driven cleanup, weak assertions on non-critical code}
file/path.go:line with the exact test code.development
Transforms vague feature ideas into precise, codebase-grounded technical requirements. Use when requirements are ambiguous/incomplete, the user struggles to describe behavior, terminology is unclear, or multiple concepts are mixed. Output is a requirements spec—NOT an implementation plan.
tools
Audit TypeScript type definitions for design debt — duplicated shapes, missing derivations, over-engineered generics, under-constrained type parameters, reinvented utility types, and disorganized type architecture. Type structure and maintainability, not type enforcement. Use when: reviewing type definitions for maintainability, reducing type duplication, simplifying over-engineered type-level logic, or reorganizing type architecture after growth.
development
Audit TypeScript test code for quality gaps — missing coverage on critical paths, brittle tests coupled to implementation, over-mocking, assertion-free tests, missing edge cases, and duplicated test setup. Focuses on test effectiveness, not production code structure. Use when: reviewing TypeScript test suites for reliability, reducing false-positive test failures, improving coverage of critical business logic, or cleaning up test debt.
tools
Audit TypeScript class and interface design for SOLID violations — god classes, rigid extension points, broken substitutability, fat interfaces, and concrete dependency chains. Focuses on responsibility assignment and abstraction fitness. Use when: reviewing class hierarchies, preparing for extension with new variants, reducing coupling between services, or improving testability of class-heavy code.