Skillkit red-green-refactor
Guides the red-green-refactor TDD workflow: write a failing test first, implement the minimum code to make it pass, then refactor while keeping tests green. Use when a user asks to practice TDD, write tests first, follow red-green-refactor, do test-driven development, write failing tests before code, or phrases like 'make the test pass', 'test coverage', or 'unit tests before implementation'.
git clone https://github.com/rohitg00/skillkit
T=$(mktemp -d) && git clone --depth=1 https://github.com/rohitg00/skillkit "$T" && mkdir -p ~/.claude/skills && cp -r "$T/packages/core/src/methodology/packs/testing/red-green-refactor" ~/.claude/skills/rohitg00-skillkit-red-green-refactor && rm -rf "$T"
packages/core/src/methodology/packs/testing/red-green-refactor/SKILL.mdRed-Green-Refactor Methodology
You are following the RED-GREEN-REFACTOR cycle for test-driven development. Every new feature, bug fix, or behavior change starts with a failing test.
The Cycle
1. RED Phase — Write a Failing Test
- Understand the requirement — what specific behavior must exist?
- Write one test asserting that behavior
- Run the test — it MUST fail (red)
- Verify the failure reason — not a syntax error, but a missing implementation
The test should be focused on ONE behavior, named descriptively, and use clear assertions.
Executable example (Jest):
// calculateTotal.test.js const { calculateTotal } = require('./calculateTotal'); describe('calculateTotal', () => { it('should apply 10% discount when total exceeds 100', () => { const items = [{ price: 60 }, { price: 60 }]; // total = 120 expect(calculateTotal(items)).toBe(108); // 120 * 0.90 }); });
Running this now produces:
Cannot find module './calculateTotal' — correct RED state.
2. GREEN Phase — Make the Test Pass
Write the minimum code needed to pass the test. Don't add anything extra.
// calculateTotal.js function calculateTotal(items) { const total = items.reduce((sum, item) => sum + item.price, 0); return total > 100 ? total * 0.9 : total; } module.exports = { calculateTotal };
Run the test — it passes. GREEN achieved. Stop here; resist adding more logic.
3. REFACTOR Phase — Improve the Code
With a passing test as your safety net, clean up the implementation. Run tests after every change.
// calculateTotal.js — refactored for clarity const DISCOUNT_THRESHOLD = 100; const DISCOUNT_RATE = 0.9; function calculateTotal(items) { const subtotal = items.reduce((sum, { price }) => sum + price, 0); return subtotal > DISCOUNT_THRESHOLD ? subtotal * DISCOUNT_RATE : subtotal; } module.exports = { calculateTotal };
Test still passes — GREEN maintained. Constants now communicate intent.
End-to-End Example: Adding a New Behavior
Next requirement: apply a 15% discount when total exceeds 200.
RED — write the failing test first:
it('should apply 15% discount when total exceeds 200', () => { const items = [{ price: 110 }, { price: 110 }]; // total = 220 expect(calculateTotal(items)).toBe(187); // 220 * 0.85 });
GREEN — extend the implementation minimally:
function calculateTotal(items) { const subtotal = items.reduce((sum, { price }) => sum + price, 0); if (subtotal > 200) return subtotal * 0.85; if (subtotal > 100) return subtotal * 0.9; return subtotal; }
REFACTOR — remove duplication with a tiered structure:
const DISCOUNT_TIERS = [ { threshold: 200, rate: 0.85 }, { threshold: 100, rate: 0.9 }, ]; function calculateTotal(items) { const subtotal = items.reduce((sum, { price }) => sum + price, 0); const tier = DISCOUNT_TIERS.find(({ threshold }) => subtotal > threshold); return tier ? subtotal * tier.rate : subtotal; }
Both tests pass — ready for the next cycle.
Workflow Steps
- Create or open the test file first
- Write ONE failing test for the smallest testable unit
- Implement minimally — just enough to pass
- Refactor if needed — while tests stay green
- Repeat for the next behavior
Decision Points
Write a new test when:
- Adding a new feature or behavior
- Fixing a bug (test the bug first, then fix it)
- Handling an edge case discovered during implementation
Don't write a test when:
- Pure refactoring (existing tests already cover the behavior)
- Non-functional changes (formatting, comments)
- Third-party library internals
Verification Checklist
- All new code has corresponding tests
- Tests fail when the feature is removed
- Tests pass consistently (not flaky)
- Code has been refactored for clarity
- No unnecessary code was added
Common Mistakes to Avoid
- Writing tests after code — defeats the design benefit of TDD
- Writing multiple tests at once — one test drives one change
- Passing tests with hacks — the test should drive good design
- Skipping the refactor phase — technical debt accumulates
- Testing implementation details — test behavior, not internals
Integration with Other Skills
- test-patterns: Patterns for structuring tests
- anti-patterns: Common testing mistakes to avoid
- debugging/root-cause-analysis: When tests reveal unexpected failures