Install
openclaw skills install @dennisrongo/write-testsAuthor tests that actually catch regressions — picks WHAT to test by risk (branch points, boundaries, error paths, money/auth/concurrency), proves every new test can fail (a test never seen red is decoration), mocks only boundaries you don't own, and pins untested legacy code with labeled characterization tests before anything else touches it. Use this skill whenever the user says "write tests", "add tests", "test this", "add coverage", "unit test this function", "increase coverage", "add a regression test", "characterization tests", "TDD this", or "/write-tests" — even if they don't explicitly say "test skill". Do not use for diagnosing a failing test (use diagnose) or reviewing existing tests as part of a diff (use code-review).
openclaw skills install @dennisrongo/write-testsAuthor tests whose only job is to fail when the behavior breaks. Everything else — coverage numbers, green checkmarks, test count — is a proxy, and every proxy here can be gamed by accident. This skill makes the non-gameable thing the deliverable: each test is proven capable of failing, targets a behavior chosen by risk, and asserts what the caller can observe.
safe-refactor).Do not auto-trigger when the user is debugging a failing test (diagnose) or reviewing test quality in a diff (code-review).
package.json scripts, *.csproj, pytest.ini, go.mod, Cargo.toml, Makefile) and run the existing suite in non-interactive mode — a test script that launches watch mode never exits and never yields a result; use the runner's single-run form (CI=true, --run, --watchAll=false, or the repo's test:ci script). Quote its summary line in your report. A result you didn't observe is tests: not run, never "passing". If the suite is already red, stop and surface it — new tests on a red suite are unverifiable.file:line and stop. Duplicating coverage is negative value: two tests break on every refactor instead of one.refund_over_balance_is_rejected, not test_refund_2). Assert observable behavior — return values, thrown errors, persisted state, emitted calls across a real boundary — never internal call order or private state.
MAX_RETRIES == 5, but "a failing call is retried 5 times and the 6th never happens").want values are the preferred shape. An expectation computed by the code under test (or its helpers) passes no matter what the code does.
expect(buildQuery({tag:'urgent'})).toBe(buildQuery({tag:'urgent'})) — mirror assertion, always true.expect(buildQuery({tag:'urgent'})).toBe('tag:"urgent"').git diff on the production sources and confirm it contains none of your mutations — only the new test files. A leftover mutation is worse than no test; the green suite can't catch the one you made it agree with.expect(userService.formatName).toHaveBeenCalledWith(user) — asserts plumbing; survives formatName returning garbage.expect(response.displayName).toBe("Smith, Jane") — asserts the observable result; survives any internal restructure that keeps behavior.destroy()/reset() called only from tests belongs in a test utility, not on the class under test. Ask: is this method called only from tests? Does this class own the resource's lifecycle? Wrong answers → test utility.// characterization: pins current (possibly wrong) behavior — see #issue. Report the suspected bug separately; changing it is a behavior change, not a test.User: "Add tests for InvoiceService.applyCredit."
Claude: Runs the suite (quotes 47 passed), reads the whole method plus the two private helpers it calls, ranks behaviors (credit > balance, negative credit, concurrent double-apply, happy path), finds the happy path already covered in InvoiceServiceTests.cs:88, writes the three missing tests, breaks the guard clause to prove each goes red, restores, quotes final green run.
User: "I need to restructure this 400-line pricing function but there are no tests."
Claude: Enumerates its branches, runs the function against boundary inputs to record actual outputs, writes characterization tests pinning them (including one output that looks off, labeled and reported separately), proves they fail against a mutated copy, then hands off to safe-refactor.
sleep()-based waits for async behavior — poll a condition or inject the clock; time-based tests are flaky by construction.*-mock test ID or that a mock element rendered — the test proves the mock exists, not that the component works.improve-codebase-architecture rather than heroically mocking through it.think-like-fable discipline throughout: effort follows risk (step 3), claims are re-derived not recognized (steps 1, 6), and the report leads with what matters.