agentleFS
TwigpineTwigpine/openclaude-skills/skills/test-writer/SKILL.md

test-writer

Skill19 starsChanged 6 months agoMITView on GitHub

Writes unit, integration, and end-to-end tests for existing or new code.

28 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use debug-fix, changelog-writer and 9 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • zebbernSkill

    debug-fix

    Find and fix a bug or issue — from any source (GitHub issue, error message, user report, or observed behavior)

    Also in 4 projects that use this

  • zbruhnkeSkill

    changelog-writer

    Maintain CHANGELOG.md with properly categorized entries. Use after implementing features, fixing bugs, or making any notable changes. Follows Keep a Changelog format.

    Also in 5 projects that use this

  • glinckerSkill

    readme-generator

    Generates comprehensive README.md files for software projects by analyzing codebase structure

    Also in 4 projects that use this

  • JohnJBorenSkill

    debugger

    Systematic debugging workflows, root cause analysis, and troubleshooting patterns

    Also in 3 projects that use this

  • get-proofpilotSkill

    context-budget

    Audits Claude Code context window consumption across agents, skills, MCP servers, and rules. Identifies bloat, redundant components, and produces prioritized token-savings recommendations.

    Also in 3 projects that use this

  • nimbalystSkill

    prd-writer

    Create structured Product Requirements Documents (PRDs) with prioritized requirements. Use when writing product specs, feature requirements, or project briefs.

    Also in 3 projects that use this

The file

We split this skill into the rules it gives an agent

6 rules. 0 are common, 4 are distinctive, and 2 are very specific to this project.

  • 0

    Common

    Most of the 27 edited versions we read keep these.

  • 4

    Distinctive

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Add tests that catch real regressions.

    line 18
  2. Distinctive:

    Write tests that test the contract, not the implementation.

    line 66
  3. Distinctive:

    Run the test in two states to prove it actually checks something: first with the implementation broken (assert the test fails), then with …

    line 79
  4. Very specific:

    Keep test runtime in mind.

    line 83
  5. Very specific:

    Write a test that pins exactly that input and assertion.

    line 126
  6. Distinctive:

    Do the assertions describe observable behavior, not internal implementation details?

    line 149

“Common” is measured: kept by at least 6 in 10 of the 27 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Test Writer

Add tests that catch real regressions. Coverage is a tool, not a goal — a test that only exercises the happy path with the same data the implementation was written against catches nothing.

Use this skill when

  • The user asks to write tests for an existing function, class, or module.
  • The user wants to add coverage for a feature or bug fix.
  • The user describes a behavior they want pinned down so it does not regress.
  • The user is writing new code TDD-style and wants the tests first.

Do NOT use this skill when

  • The user is debugging a known failure. Use debugging — once the root cause is clear, come back here to write the regression test.
  • The user has not yet implemented the behavior and the design is unsettled. Use a coding skill to pin the design first.
  • The user wants tests for code they are about to delete.

Procedure

  1. Identify the unit under test. Be explicit: "the parseDate function in src/date.ts", "the /users/:id GET handler", "the checkout flow from add-to-cart to receipt". Vague targets produce vague tests.
  2. Pick the right test type:
    • Unit: pure function, single class, mockable boundary. Fastest to run, cheapest to maintain. Default to unit tests when the logic is mostly in-process.
    • Integration: code that crosses a boundary you cannot reasonably mock (database, queue, file system). Use a real dependency in a controlled environment (testcontainers, in-memory SQLite if the queries match).
    • End-to-end: whole-system behaviors the user sees (full HTTP request, full UI click path). Expensive — reserve for the handful of flows that earn the cost. Each level has a place. Pushing logic into unit-testable functions is usually a better answer than writing more e2e tests.
  3. Enumerate cases before writing assertions. For each behavior list:
    • Happy path — typical input, typical output.
    • Boundaries — empty, single, max, just-over-max.
    • Edge cases — null, undefined, negative numbers, unicode, duplicates, ordering, concurrency.
    • Error paths — invalid input, dependency failures, timeouts.
    • Idempotency / side effects — does running twice change the result? Should it?
  4. Write tests that test the contract, not the implementation. Assert on observable behavior (return values, emitted events, written rows) — not on which internal method was called. Tests that over-specify implementation break on every refactor and teach future readers nothing.
  5. Pick fixtures and factories deliberately. Prefer minimal, purpose-built fixtures over shared "kitchen sink" objects. A test that fails for unclear reasons usually started with a fixture that carries more state than the test needs.
  6. Choose assertions that fail descriptively. expect(result).toEqual(expected) beats expect(result.length > 0).toBe(true) — when the second one fails, you learn nothing. Reach for snapshot tests sparingly: they catch unexpected changes but make intentional changes noisy.
  7. Run the test in two states to prove it actually checks something: first with the implementation broken (assert the test fails), then with the implementation correct (assert the test passes). A test that passes against both implementations is decorative.
  8. Keep test runtime in mind. A suite that takes 20 minutes to run gets skipped. Move slow setup behind beforeAll, parallelize what is parallel-safe, prefer in-memory fakes for unit-level tests of code that talks to a slow boundary.
  9. Be deliberate about what to mock. Mock external services you do not own; do not mock the code under test or its immediate collaborators if you can use the real thing cheaply. Over-mocked tests pass without exercising any real code path.
  10. For each test, write a name that describes the behavior, not the function. parses an ISO date in UTC reads better than test_parseDate_1. The test runner output becomes a readable spec of the system.
  11. Group related tests with describe blocks that name the unit under test. Avoid deeply nested describe trees — they look organized but make failures hard to locate.

Examples

In scope: "Add unit tests for parseDate in src/date.ts."

→ Read parseDate. Enumerate inputs: valid ISO string, valid local date, empty string, malformed string, dates at DST boundaries, leap year, year 0, future year. Write one assertion per case. Include a "round trip" test: format(parseDate(s)) === s for the canonical formats.

In scope: "Pin down the behavior of the checkout flow."

→ This is integration- or e2e-shaped. Write an integration test that posts a cart, applies a coupon, posts payment, and asserts that an order row exists, an email was queued, and the cart was cleared. Skip the UI rendering details — those belong in a separate UI test.

Out of scope: "Why is this test flaky?"

→ Flakes are a debugging task. Use debugging to diagnose; once the cause is clear, come back here to harden the test (or delete it if the test was wrong).

In scope: "We just fixed a bug — add a regression test."

→ The diagnosis already produced the smallest input that reproduces. Write a test that pins exactly that input and assertion. Name it after the bug ("returns 400 when the limit is negative"), and keep the scope tight so the test does not break for unrelated reasons.

Out of scope: "Write tests for code I'm about to delete."

→ Don't.

Out of scope: "Generate 100% coverage for this module."

→ Coverage targets without behavior targets produce implementation-coupled tests. Ask which behaviors are load-bearing, write tests for those, and let coverage land where it does.

Self-check before responding

  • Is the unit under test stated precisely?
  • Did I pick the smallest test type that meaningfully exercises the behavior?
  • Did I enumerate happy-path, boundary, edge-case, and error-path cases before writing assertions?
  • Do the assertions describe observable behavior, not internal implementation details?
  • Did I confirm the test fails when the implementation is broken?
  • Are fixtures minimal and purpose-built, not shared kitchen-sink objects?
  • Will the test still pass on a refactor that preserves behavior?
  • Will the test fail descriptively, so a future reader can diagnose from the failure message alone?
  • Is the total runtime cost worth the regression protection?

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.