agentleFS
SWEStashSWEStash/swe-workflow-skills/skills/tdd-workflow/SKILL.md

tdd-workflow

Skill1 starsChanged 5 days agoMITView on GitHub

Guide test-driven development with red-green-refactor. For NEW code via test-first — use test-suite-design for adding tests to existing code.

128 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use brand-discovery, configure-ecc and 10 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.
  • ysyecustSkill

    brand-discovery

    Use when a brand needs to discover or articulate its identity through structured multi-session interviews. Covers purpose, positioning, audience, personality, voice, narrative, and founder-brand tension across 8 modules using laddering, 5 Whys, and projective techniques. Produces a resumable session with disk-persisted state and a master brandbook (90_SYNTHESIS.md).

    Also in 6 projects that use this

  • royaluniondesign-sysSkill

    configure-ecc

    Interactive installer for Everything Claude Code — guides users through selecting and installing skills and rules to user-level or project-level directories, verifies paths, and optionally optimizes installed files.

    Also in 12 projects that use this

  • junimnjwSkill

    ralphinho-rfc-pipeline

    RFC-driven multi-agent DAG execution pattern with quality gates, merge queues, and work unit orchestration.

    Also in 12 projects that use this

  • loulanyueSkill

    nuxt4-patterns

    Nuxt 4 app patterns for hydration safety, performance, route rules, lazy loading, and SSR-safe data fetching with useFetch and useAsyncData.

    Also in 10 projects that use this

  • royaluniondesign-sysSkill

    content-hash-cache-pattern

    Cache expensive file processing results using SHA-256 content hashes — path-independent, auto-invalidating, with service layer separation.

    Also in 16 projects that use this

  • RojiosSkill

    dart-flutter-patterns

    Production-ready Dart and Flutter patterns covering null safety, immutable state, async composition, widget architecture, popular state management frameworks (BLoC, Riverpod, Provider), GoRouter navigation, Dio networking, Freezed code generation, and clean architecture.

    Also in 7 projects that use this

The file

Show its rules and text

We split this skill into the rules it gives an agent

15 rules. 0 are common, 15 are distinctive, and 0 are very specific to this project.

  • 0

    Common

    Most of the 117 edited versions we read keep these.

  • 15

    Distinctive

    This author's own choices. Worth a look.

  • 0

    Very specific

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

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Before writing any test, create a list of behaviors to test.

    line 41
  2. Distinctive:

    Write exactly one test that describes the next behavior.

    line 63
  3. Distinctive:

    Follow the Arrange-Act-Assert pattern (or Given-When-Then)

    line 66
  4. Distinctive:

    Test behavior, not implementation (assert on outputs, not internal state)

    line 67
  5. Distinctive:

    Run the test and confirm it fails.

    line 70
  6. Distinctive:

    Write the minimum code to make the failing test pass.

    line 74
  7. Distinctive:

    Use the simplest possible data structure

    line 77
  8. Distinctive:

    Run all tests (not just the new one).

    line 81
  9. Distinctive:

    Remove duplication in test setup (use fixtures/helpers)

    line 93
  10. Distinctive:

    Ensure tests are independent (no shared mutable state)

    line 95
  11. Distinctive:

    Run all tests after each refactoring step.

    line 97
  12. Distinctive:

    After completing all items, do a final review — see references/test-quality.md.

    line 103
  13. Distinctive:

    Integration tests: Test how components work together.

    line 109
  14. Distinctive:

    Outside-in TDD: Start with an acceptance test (failing), then drive the implementation with unit tests.

    line 111
  15. Distinctive:

    Inside-out TDD: Start with the core domain logic, build outward.

    line 113

“Common” is measured: kept by at least 6 in 10 of the 117 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

TDD Workflow

Guide implementation through the red-green-refactor cycle. TDD produces code that is testable by design, has a living specification, and tends toward simpler solutions because you only write what's needed to pass the next test.

⛔ The Iron Law

No production code without a failing test you have watched fail.

If you wrote code before the test, set it aside and restart from the test — stash it rather than delete it (git stash, or a scratch file) so the work is recoverable but out of sight; don't keep it "as reference" or "adapt it" while writing the test. A deadline is not an exception to this — it is the situation the rule exists for. A test you didn't watch fail proves nothing: you don't know whether it tests the right thing. This is the one rule that the rest of the workflow protects.

The Cycle

┌──────────────────────────────────┐
│           RED                     │
│  Write a failing test that        │
│  describes the next behavior      │
├──────────────────────────────────┤
│           GREEN                   │
│  Write the minimum code to        │
│  make the test pass               │
├──────────────────────────────────┤
│           REFACTOR                │
│  Improve the code while           │
│  keeping all tests green          │
└──────────────────────────────────┘
         ↑                    │
         └────────────────────┘

Workflow

Step 0: Plan the Test List

Before writing any test, create a list of behaviors to test. Derive this from acceptance criteria or the task description. Order from simplest to most complex:

  1. Happy path — the simplest valid scenario
  2. Edge cases — boundary values, empty inputs, single items
  3. Error cases — invalid input, missing resources, permission failures
  4. Integration points — interactions with other components

Exit condition — one line, then keep going in the same response: "Test list: <n> behaviors, starting with <the simplest one>."

This step is not a gate on delivering. The test list is the roadmap — each item becomes one red-green-refactor cycle — but presenting it is not the deliverable. Run the first cycle in the same response: a real failing test body, the minimum code that passes it, and either a named refactor or an explicit "nothing to refactor yet". A reply that stops at test names and input values has delivered nothing testable.

Where a requirement is under-specified, state the assumption and encode it in the test — a test the user corrects beats a question they must answer. Ask only when the assumption would change what the code is, not merely a value you can name in one line.

Step 1: RED — Write a Failing Test

Write exactly one test that describes the next behavior. The test should:

  • Have a descriptive name that reads like a specification: test_user_cannot_login_with_expired_password
  • Follow the Arrange-Act-Assert pattern (or Given-When-Then)
  • Test behavior, not implementation (assert on outputs, not internal state)
  • Fail for the right reason (missing function, wrong return value — not syntax error)

Run the test and confirm it fails. Show the failure output to the user. If the test passes immediately, either the behavior already exists or the test is wrong.

Step 2: GREEN — Make It Pass

Write the minimum code to make the failing test pass. This is critical — resist the urge to write the "right" solution. Minimum means:

  • Hard-code a return value if that's enough
  • Use the simplest possible data structure
  • Skip error handling if no test requires it yet
  • Ignore performance, elegance, or future needs

Run all tests (not just the new one). Everything must be green.

Step 3: REFACTOR — Improve Under Green

Now improve the code while all tests stay green. Look for:

  • Duplication → Extract methods, constants, or shared setup
  • Naming → Rename to reveal intent
  • Complexity → Simplify conditionals, flatten nesting
  • Responsibility → Extract classes/modules if a function does too much

Also refactor the tests:

  • Remove duplication in test setup (use fixtures/helpers)
  • Improve test names if the behavior is clearer now
  • Ensure tests are independent (no shared mutable state)

Run all tests after each refactoring step. If anything breaks, undo the last change immediately.

Step 4: Repeat

Pick the next item from the test list. Return to Step 1.

After completing all items, do a final review — see references/test-quality.md.

Adapting TDD to Different Contexts

Unit tests (default): Test a single function or class in isolation. Mock external dependencies. Fast feedback loop (milliseconds).

Integration tests: Test how components work together. Use for database queries, API endpoints, message handling. Slower but catch wiring bugs.

Outside-in TDD: Start with an acceptance test (failing), then drive the implementation with unit tests. Useful when you know the desired API or user interaction.

Inside-out TDD: Start with the core domain logic, build outward. Useful when the domain is complex and the interface is flexible.

Suggest the appropriate approach based on the task. Default to unit tests unless the task is primarily about integration.

What NOT to TDD

TDD is a design tool, not a coverage tool. Don't TDD:

  • Trivial getters/setters
  • Framework configuration
  • Third-party libraries themselves — test your code's use of them at the integration level; don't re-assert what the library's own tests already cover (its compression, its persistence, its parsing)
  • UI layout (visual regression tools are better here)

Principles Applied

  • YAGNI: The test list prevents building more than needed. If there's no test for it, don't build it.
  • KISS: Minimum code to pass forces simplicity.
  • Functional Independence: Tests that mock dependencies encourage decoupled design.
  • DRY: Refactoring phase explicitly targets duplication.
  • FIRST: Tests should be Fast, Independent, Repeatable, Self-validating, and Timely — see references/test-quality.md for the full checklist and test smell detection.

Rationalizations to reject

These are the excuses that lead to skipping the test. None of them hold up.

ExcuseReality
"It's too simple to test"Simple code still breaks. The test costs 30 seconds; the regression costs an afternoon.
"I'll add the tests after"Tests written after the code pass immediately — they prove the code does what it does, not what it should.
"I already tested it manually"Manual checks aren't repeatable and don't guard against the next regression.
"Deleting working code is wasteful"Sunk cost. Unverified code is debt, not progress.
"Tests-after achieve the same thing"Tests-first ask "what should this do?"; tests-after ask "what does this do?" — different specs.
"TDD will slow me down"Debugging untested code is slower than writing the test first.
"We ship in 30 minutes — no time for this"The deadline is when the law matters most, not when it lapses. A demo that ships on unverified code is how the bug reaches production with nobody watching. Test-first on the one behavior that matters beats tests-after on all of them.
"But the code is already written and it works"You do not know that — you watched it work once, by hand. Stash it, don't delete it (git stash, or move it to a scratch file): it stays recoverable and out of sight so you cannot copy from it while writing the test. Then write the failing test, watch it fail, and re-derive. If the stash turns out to match, you lost two minutes and gained a test that means something.

Red flags — stop and correct course

  • You're writing implementation and will "get to the test next."
  • A new test passes the first time you run it (you never saw RED).
  • You can't explain why the test failed in the RED phase.
  • You're glancing at not-yet-deleted draft code while writing the "test-first" version.
  • You're editing the test to make it pass — the test was the spec; change the code, or escalate if the spec itself is wrong.

Cross-Skill References

  • test-suite-design — adding tests to existing code (this skill is for new code, test-first)
  • bug-investigating — write a regression test for a found bug using this cycle
  • verification-before-completion — the GREEN step is this gate: watch the test pass for real

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.