Loading...
Loading...
Audit an existing test suite for anti-patterns — tautological mock round-trips, weak assertions (toBeDefined / assertNotNull), implementation coupling, flaky timing, snapshot rubber-stamping, and tests claiming guarantees they cannot provide — and report a keep / tighten / rewrite / delete verdict per test.
npx skill4agent add edloidas/skills tests-auditallowed-tools| Direction violated | Failure mode | Typical shapes |
|---|---|---|
| Fails when nothing broke | False alarm — erodes trust, blocks refactoring | implementation coupling, over-mocking, flaky timing, order dependence |
| Green when something broke | False confidence — coverage without protection | tautologies, weak asserts, snapshot rubber-stamps, self-fulfilling setups, over-claimed guarantees, trivia tests |
<<=toHaveBeenCalledWithverifynew Date()review:changes-review.skip@Disabled.onlyreferences/audit-procedure.mdreferences/anti-patterns.md| Verdict | When |
|---|---|
| Keep | Passes the gate |
| Tighten | Right contract, weak execution — imprecise asserts, bad name, sleep |
| Rewrite | Real contract worth pinning, but the test pins implementation or a mock |
| Delete | No contract sentence, duplicate coverage, trivia, rotting disabled test |
references/audit-procedure.mdreferences/audit-procedure.mdreferences/writing-tests.md| Smell | Verdict → fix |
|---|---|
| Mock returns X, assert X comes back | Delete, or Rewrite against the translation the module performs |
| Name/CI claims a property (complexity, perf, security) the assert can't measure | Rewrite to what it does pin + rename, or Delete the claim |
| Arrange — or a grep of the SUT's own source — establishes what the Assert checks | Rewrite around the real producer: run it, inspect the artifact |
All assertions live inside | Tighten: |
| Property a constant or identity function would satisfy | Tighten to two-sided/metamorphic, or Delete |
| N feature tests all re-proving one mechanism | Not a finding — suite-level observation only |
| Expected value computed with SUT's formula | Tighten: replace with hand-computed constant |
| Tighten: assert the precise value or shape |
| Asserting internal call order/counts (undocumented) | Rewrite against observable output, or Delete |
| Mocking code you own (incl. whole UI libraries) | Rewrite with real collaborators; mock only the boundary |
| 300-line snapshot nobody reads | Rewrite as explicit asserts on the parts that matter |
| Tighten: fake timers, injected clock, condition-based waits |
| Tighten: table test, or split into one test per branch |
| Loop over cases with one assert (which case failed?) | Tighten: |
Giant | Tighten: builders with defaults; DAMP over DRY |
| Tighten: rename to the rule the bug violated |
| Test depends on a previous test's state | Rewrite: each test arranges its own world |
e2e: | Tighten: assert the outcome explicitly |
| Test asserts an acknowledged-wrong value ("should be 4, left as is") | Report separately: that's a bug, not a test defect |
| Delete (git remembers) — Rewrite if its intent names an uncovered promise |
| Getters, framework wiring, generated code under test | Delete — cost > 0, information = 0 |
references/anti-patterns.mdreferences/audit-procedure.mdreferences/anti-patterns.mdreferences/writing-tests.md