Test-Driven Development Skill Rules: A Complete Guide to the TDD Workflow
The test-driven-development skill requires you to write a failing test before any production code, implement the minimal code to pass, then refactor while keeping tests green.
The obra/superpowers repository defines a rigorous, step-by-step workflow for the test-driven-development skill in skills/test-driven-development/SKILL.md. This skill mandates a strict cycle of RED-GREEN-REFACTOR that must be followed for every new feature, bug fix, or behavioral change. Below are the mandatory rules derived directly from the source code analysis.
The Iron Law: No Production Code Without a Failing Test
The foundational rule of the test-driven-development skill is absolute: never write production code before a failing test exists. This "Iron Law" ensures that every line of production code is justified by a verifiable requirement. According to the skill definition at lines 31-36 of SKILL.md, a failing test proves that the test is actually checking the intended behavior and that the functionality is genuinely missing.
The RED Phase: Writing the Failing Test
During the RED phase, you must write one minimal test that demonstrates the desired behavior. The test must have a clear name, cover a single behavior, and use real code rather than mocks unless absolutely unavoidable.
As defined in skills/test-driven-development/SKILL.md (lines 71-88), the test must fail for the right reason—a test failure indicating missing functionality, not a runtime error or syntax mistake.
test('retries failed operations 3 times', async () => {
let attempts = 0;
const operation = () => {
attempts++;
if (attempts < 3) throw new Error('fail');
return 'success';
};
const result = await retryOperation(operation);
expect(result).toBe('success');
expect(attempts).toBe(3);
});
The GREEN Phase: Minimal Implementation
Once the test fails for the correct reason, you must implement the smallest amount of code needed to make the test pass. Do not add extra features, refactor, or "improve" the code during this stage.
According to lines 30-34 of SKILL.md, the goal is to get to green as quickly as possible, even if the implementation is naive or incomplete. The following example from the skill documentation shows the minimal implementation for the retry logic:
async function retryOperation<T>(fn: () => Promise<T>): Promise<T> {
for (let i = 0; i < 3; i++) {
try {
return await fn();
} catch (e) {
if (i === 2) throw e;
}
}
throw new Error('unreachable');
}
The REFACTOR Phase: Cleaning Up
After the test passes, you enter the REFACTOR phase. Here, you clean up the implementation while keeping tests green. Remove duplication, improve naming, extract helpers, and optimize performance—but never add new behavior during refactoring.
As noted in skills/test-driven-development/SKILL.md (lines 85-92), the test suite acts as a safety net, ensuring that refactoring does not introduce regressions.
// Extracted helper for retry logic (example)
function attempt<T>(fn: () => Promise<T>, retries: number): Promise<T> {
// ...implementation...
}
Verification Checklist and Red Flags
Before marking work as complete, the test-driven-development skill requires you to verify adherence using a checklist defined at lines 127-135 of SKILL.md. If any rule is broken, you must discard the code and start over.
Key red flags that trigger an immediate abort include:
- Writing code before writing a test
- Writing a test after the code is already working
- Seeing a test pass immediately (indicating the test is not actually testing new behavior)
- Rationalizing shortcuts such as "too simple to test" or "I'll test after"
Summary
The test-driven-development skill in obra/superpowers enforces a disciplined workflow through these key principles:
- Iron Law: Never write production code without a failing test first
- RED Phase: Write one minimal, clearly-named test that fails for the right reason
- GREEN Phase: Implement the smallest amount of code to pass the test
- REFACTOR Phase: Clean up the code while keeping all tests green
- Zero Tolerance: If you break any rule, discard the code and restart the cycle
Frequently Asked Questions
What happens if I write production code before writing a test?
According to the test-driven-development skill rules in skills/test-driven-development/SKILL.md, you must immediately discard that code and start over. Writing production code before a failing test violates the Iron Law and invalidates the safety net that proves your tests actually verify the intended behavior.
Can I use mocks when writing tests under the TDD skill?
The skill prefers real code over mocks unless mocks are absolutely unavoidable. As documented in the RED phase guidelines, tests should use actual implementations to ensure they verify real behavior rather than implementation details. The companion file skills/test-driven-development/testing-anti-patterns.md provides specific guidance on when mocking becomes harmful.
Why must I delete code if I accidentally make a test pass immediately?
An immediate pass indicates the test is not actually exercising new functionality or that the functionality already exists. The VERIFY RED step in SKILL.md requires confirming that tests fail for the right reason before proceeding. If a test passes without new code, you cannot prove the test would catch a regression, violating the core safety mechanism of TDD.
Is refactoring allowed to change the public API of the code?
No. The REFACTOR phase explicitly forbids adding new behavior or changing existing behavior. As defined in skills/test-driven-development/SKILL.md, refactoring should improve internal structure, naming, and remove duplication while keeping all tests passing. Any API changes require a new RED-GREEN-REFACTOR cycle starting with a failing test.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →