refine-tests
SkillMediaReviews existing test code for conformance to the test-designing-guide and test-writing-guide, then applies the refinements. Use this skill when the user wants to review or refine existing test code so it follows the project's test design and writing conventions. Typically invoked as `/refine-tests <PATH>`.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the refine-tests skill
What this skill tells your AI
The instructions your AI receives, as published by nowsprinting/unity-coding-skills in skills/refine-tests/SKILL.md and read by ahel’s review.
Reviews existing test code for conformance to the test-designing-guide and test-writing-guide, then applies the refinements.
Scope Check
This skill is for refining existing tests for conformance to the guides. If the request is out of scope, redirect:
- Adding tests for a new feature or spec change → use
/plan-featureinstead - A failing test, or a test that verifies incorrect behavior → use
/fix-buginstead
Input
One or more file path arguments. Resolve them to the concrete set of test files to review before proceeding.
If no path argument is given, use AskUserQuestion to ask the user for the targets. Do not derive targets from git status — that would silently widen the scope beyond what was requested.
Workflow
Recording implementation notes: Notes for this run go in /tmp/refine-tests-notes-$CLAUDE_CODE_SESSION_ID.md. Immediately before your first append in this run — and only then — delete that file if it exists (usually it will not), so this run starts from an empty one: the session id is shared by every /refine-tests run in the session, so an earlier run abandoned before Step 7 would otherwise leak its notes into this one.
While working through Steps 5–6, whenever one of the following occurs, immediately append a line to that file — do not wait until the end to reconstruct these from memory:
- A Finding was ambiguous, or proved wrong once applied, and you made a judgment call → Design decisions
- You intentionally departed from a Finding, and why → Deviations
- You considered alternatives and chose one, and why → Tradeoffs
- You changed production code — a method demoted to
private, a dead test-only seam removed, or any other production edit — and why → Production code changes
Append with Bash so the shell expands $CLAUDE_CODE_SESSION_ID — the Write tool cannot append and does not expand environment variables:
cat >> "/tmp/refine-tests-notes-$CLAUDE_CODE_SESSION_ID.md" <<'EOF'
- **Production code changes**: <one line>
EOF
When a step delegates to another skill (/simplify and /resolve-diagnostics in Step 6), append the note yourself from what it returns — they do not write to this file.
Step 1: Read the Target Tests
Launch Explore agent(s) to read the target test file(s) and the production code they exercise. Reading the production code is necessary to judge layer-appropriateness and structural-vs-spec-based issues.
Step 2: Conformance Review
Load the test-designing-guide and test-writing-guide skills. Apply all rules that are verifiable from the test code alone — no requirements document is available.
The following sections of test-designing-guide require requirements input or production-design changes and are out of scope:
- Section 5 (requirements coverage / traceability / same-layer witness)
- Section 6 (design-document output format)
- Section 7 (Testability Assessment — remedies require production-design changes)
Produce a Findings list. Each finding records:
- Location: file path + test method name
- Category: which guide + rule violated, or duplicate test (see Step 3)
- Concrete proposed change
Step 3: Duplicate Detection
Compare the target test files against each other and against other tests in the same test class.
A true duplicate has both of the following in common with another test:
- Same condition — identical setup / input
- Same assertion — identical observation / expected value
Do NOT flag tests that share only one:
- Different condition → not a duplicate
- Same condition but different assertion → not a duplicate
For each true duplicate pair, append a Finding to the Findings list from Step 2:
- Proposed change: delete the redundant test (the less accurately named one) and keep the more accurately named one. Name both explicitly.
- Do NOT propose merging same-condition tests into a single multi-assert test.
Exception — defer to Step 4: If one test in a duplicate pair is [Category("Internal")] and the other is a public-seam test, do not apply the name-quality tiebreaker here. Do not delete the public-seam test on naming grounds. Defer the pair to Step 4, which always keeps the public-seam test.
Step 4: Seam Redundancy — Internal-Method Tests
Test through the same seam production code uses. A [Category("Internal")] test exercises an internal method directly. For each such test in the targets, append Findings via two passes. Overriding rule: never trade coverage for a tidier seam; when in doubt, keep the test (and keep internal).
Layer scope: This step operates within the unit test layer only. Tests marked [Category("Integration")] or [Category("VisualVerification")] run under different execution contexts and are not candidates for a covering test — do not consider them when searching for a public-seam test that covers the same scenario.
Pass 1 — classify each [Category("Internal")] test:
- A public-seam test already covers it (from the test code alone): a separate unit test asserts the same observable outcome for an equivalent scenario through a public method → Finding: delete the internal test, keep the public-seam test (name both).
- No public-seam test covers it — using the production code read in Step 1: a. Not fully observable through public — a public caller masks or only partially exposes the asserted outcome → keep the internal test; no Finding. "Cheap to extract" ≠ "observable publicly." b. Sanctioned extraction — the method takes 3 or more parameters (a heuristic; the real trigger is that several independent conditions combine so exhaustive public-seam coverage cost explodes — this can also occur with fewer parameters that each take many values, and may not apply when the extra parameters don't drive branching), and it isolates cohesive sub-logic (a pure computation or decision that depends on only 1–2 of those inputs) → keep the internal test; no Finding. Applies regardless of how the test was created. c. Otherwise (consolidatable into public) → Finding: rewrite the test to assert the same observable outcome through the public method (merge with an existing public-seam test where natural). The Finding must name explicitly: the target public method to go through, the existing public-seam test to merge into (or state that a new test method is created, with its name), and the observable outcome to assert — the implementer applies the Finding as written and must not need to re-derive these decisions.
Pass 2 — visibility sweep: for each internal method whose direct internal test goes away in Pass 1 (deleted via 1 or moved via 2c), search the whole solution for usages (internal is visible cross-assembly via InternalsVisibleTo — check other production and test assemblies, not just files in scope):
- Test-only seam wrapped in
#if UNITY_INCLUDE_TESTS, test now gone → Finding: remove the dead seam. - Nothing outside the declaring class still needs
internalaccess → Finding: demote the method toprivate(do not break any#ifconditional compilation). - Any doubt, or any remaining cross-assembly
internaluse → leave itinternal; no Finding.
Pass 2 Findings change production code — record the file path + method explicitly.
Step 5: Modify Tests
- Load the
test-writing-guideskill — and thecode-writing-guideskill if the Findings include production changes; do not rely on automatic skill triggering - Apply the changes described in the Findings list from Steps 2–4 — test edits, plus any production visibility changes (a method demoted to
private, or a dead test-only seam removed) - Run tests with
/run-testsand confirm all pass
Step 6: Refactoring
- Run the Claude Code built-in
/simplifyskill (Skill({skill: "simplify"})— not a plugin skill) to apply quality improvements to the modified code - Run tests with
/run-testsand confirm all pass - Run
/resolve-diagnosticswith the files modified in Step 5 — compute the list after/simplifyfinishes, so its edits are covered too - Commit all remaining changes to git
Step 7: Implementation Notes
Read/tmp/refine-tests-notes-$CLAUDE_CODE_SESSION_ID.mdif it exists — if it was never created, every category is "None"- Report its entries to the user in chat under
## Implementation Notes— one bold sub-heading per category, each followed by a bullet list. Always include all five categories in this order: Design decisions, Deviations, Tradeoffs, Production code changes, Open questions. Write- Nonefor any category with nothing recorded, and add any last-minute Open questions before finalizing - Delete the temporary notes file if it exists
Signals
- GitHub stars
- 21
- Forks
- 3
- Last commit
- Aug 2026
Advanced
- Catalog kind
- skill
- Gateway key
refine-tests- Source
- github.com/nowsprinting/unity-coding-skills