Test writing
Skill scotthavird/claude-code-template/.claude/skills/test-writing
Activates when writing, modifying, or discussing tests. Enforces testing discipline - tests must fail for the right reason, isolate the unit under test, and cover edge cases.From its SKILL.md
npx -y skills add scotthavird/claude-code-template --skill test-writingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 7 stars7 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
2.6 KB, as published. Nobody here has run it
Test Writing Skill
You write tests that would pass code review at a senior engineer's desk.
Principles
- Every test must be able to fail. If mutating the code under test doesn't break the test, the test is worthless.
- Isolate the unit. Stub external services and the clock, not internal collaborators. Integration tests are different from unit tests — be explicit about which you are writing.
- Arrange–Act–Assert. One act per test. Multiple asserts OK if they describe one behavior.
- Name tests as specifications.
it('retries 3x on 500')beatsit('works'). - Cover the boundary. Empty input, null, max length, unicode, timezone, concurrent calls, error from dependency.
- No shared mutable state between tests. Reset fixtures in beforeEach.
What to flag when you see it
- Tests that pass by asserting on mocked return values — they're tautological.
expect(true).toBe(true)orexpect(fn).not.toThrow()as the only assert.- Snapshot tests where the snapshot covers everything — the test will pass even when the behavior changes.
- Sleep-based waits (
await sleep(100)) — use fake timers or deterministic hooks. - Tests that access
process.envwithout setting/resetting it.
Framework idioms
Jest / Vitest
describe('RefundProcessor', () => {
beforeEach(() => vi.useFakeTimers());
afterEach(() => vi.useRealTimers());
it('schedules retry after a 429', async () => {
const stripe = { refunds: { create: vi.fn().mockRejectedValueOnce({ status: 429 }) } };
const processor = new RefundProcessor(stripe);
const p = processor.refund('ch_1', 1000);
await vi.advanceTimersByTimeAsync(1000);
expect(stripe.refunds.create).toHaveBeenCalledTimes(2);
});
});
Pytest
def test_refund_retries_on_429(stripe_client, fake_clock):
stripe_client.refunds.create.side_effect = [StripeRateLimit(), {"id": "re_1"}]
processor = RefundProcessor(stripe_client, clock=fake_clock)
result = processor.refund("ch_1", 1000)
fake_clock.advance(1)
assert stripe_client.refunds.create.call_count == 2
assert result["id"] == "re_1"
When reviewing tests
Run git diff on the test file and ask: if I reverted the production
change this test was written for, would this test fail? If no — rewrite.