agentleFS
slowdinislowdini/slow-powers/skills/working-with-tdd/SKILL.md

working-with-tdd

Skill2 starsChanged 50 days agoMITView on GitHub

Use when implementing any feature, refactoring, or writing a bugfix.

The file

We split this skill into the rules it gives an agent

12 rules. About 0 are common, 11 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈11

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

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

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Write the test first. Watch it fail.

    line 8
  2. Distinctive:

    Write production code before the test?

    line 12
  3. Distinctive:

    Write one minimal, focused test showing what the behavior *should* do.

    line 25
  4. Distinctive:

    Use real code and real inputs.

    line 26
  5. Distinctive:

    Before committing a test, scan it against the Testing anti-patterns table below.

    line 27
  6. Very specific:

    Run the test command: npm test / pytest / go test.

    line 31
  7. Distinctive:

    MANDATORY: Verify it fails for the expected reason (for example, a function is undefined or a value is incorrect), not because of a typo or …

    line 32
  8. Distinctive:

    Write the simplest possible implementation to make the test pass.

    line 34
  9. Distinctive:

    Avoid over-engineering or speculative optimization.

    line 35
  10. Distinctive:

    Run the test suite. Verify the test passes, and no regressions are introduced.

    line 37
  11. Distinctive:

    Keep the test suite green.

    line 40
  12. Distinctive:

    All of these mean: delete code.

    line 112

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “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-driven development (TDD)

Write the test first. Watch it fail. Write minimal code to pass. Refactor.

THE IRON LAW: NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST.

Write production code before the test? Delete it. Start over. Do not keep it for "reference" or "adapt" it. Delete means delete.

Violating the letter of the rules is violating the spirit of the rules.

REQUIRED PREREQUISITE: You must have already completed slow-powers:working-in-isolation — establish an isolated workspace before writing any test or production code.

REQUIRED NEXT SKILL: You must complete slow-powers:verifying-development-work next, after the TDD implementation work is done and before claiming the task is complete or handing work back to the user.


Red-green-refactor cycle

  1. RED — Write a failing test:
    • Write one minimal, focused test showing what the behavior should do.
    • Use real code and real inputs; avoid mocks unless absolutely unavoidable. Before committing a test, scan it against the Testing anti-patterns table below; if it matches a row, read the named section of the testing anti-patterns reference first.
  2. Verify RED — Watch it fail:
    • Run the test command: npm test / pytest / go test.
    • MANDATORY: Verify it fails for the expected reason (for example, a function is undefined or a value is incorrect), not because of a typo or build error.
  3. GREEN — Write minimal code:
    • Write the simplest possible implementation to make the test pass.
    • Avoid over-engineering or speculative optimization.
  4. Verify GREEN — Watch it pass:
    • Run the test suite. Verify the test passes, and no regressions are introduced.
  5. REFACTOR — Clean up:
    • Clean up names, remove duplication, and extract helper methods.
    • Keep the test suite green. Do not add new behavior during refactoring.

Example: code vs. mock testing

Good (focuses on real behavior)

test('retries failed operations 3 times', async () => {
  let attempts = 0;
  const operation = async () => {
    attempts++;
    if (attempts < 3) throw new Error('fail');
    return 'success';
  };
  const result = await retryOperation(operation);
  expect(result).toBe('success');
  expect(attempts).toBe(3);
});

Bad (focuses on mock implementation detail)

test('retry works', async () => {
  const mock = jest.fn()
    .mockRejectedValueOnce(new Error())
    .mockRejectedValueOnce(new Error())
    .mockResolvedValueOnce('success');
  await retryOperation(mock);
  expect(mock).toHaveBeenCalledTimes(3);
});

Testing anti-patterns — scan before you commit a test

While writing or changing a test, check it against this table. If a row matches, read the named section of the testing anti-patterns reference before moving on — mocks are the most common source of these, but not the only one.

If your test…Anti-patternSection to read
asserts on a mock / *-mock element instead of real outputtesting mock behaviorTesting mock behavior
needs a method on a production class that only tests calltest-only methods in productionTest-only methods in production
mocks a method without knowing its side effectsmocking without understandingMocking without understanding
uses a mock with only the fields you happen to needincomplete mocksIncomplete mocks
is written after the implementation, with no failing test firsttests as afterthoughtTests as afterthought
stubs by call order (...Once chains) or asserts "call N" / "the last call"order-dependent mocks/assertionsOrder-dependent mocks and assertions
has more mock setup than test logicover-complex mocksWhen mocks become too complex

Common rationalizations

ExcuseReality
"This is too simple to test"Simple code breaks. Test takes 30 seconds.
"I'll test after to verify it works"Tests passing immediately prove nothing.
"I already know what the code should look like"Knowing the answer doesn't mean the requirement is specified.
"Testing this would be trivial"Trivial tests are cheap; skipping them costs later.
"I'll add tests later, I promise"Later never comes. The codebase drifts.
"The spirit of TDD is what matters, not the letter"Violating the letter is violating the spirit.

Red flags — STOP and start over

  • Code before test
  • "I already manually tested it"
  • "Tests after achieve the same purpose"
  • "It's about spirit not ritual"
  • "This is different because..."

All of these mean: delete code. Start over with TDD.

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.