From xpowers
Enforces RED-GREEN-REFACTOR cycle for implementing features or fixing bugs. Requires tests to fail before writing production code.
How this skill is triggered — by the user, by Claude, or both
Slash command
/xpowers:test-driven-developmentThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
<skill_overview>
<skill_overview> Write the test first, watch it fail, write minimal code to pass. If you didn't watch the test fail, you don't know if it tests the right thing. </skill_overview>
<rigidity_level> LOW FREEDOM - Follow these exact steps in order. Do not adapt.
Violating the letter of the rules is violating the spirit of the rules. </rigidity_level>
<quick_reference>
| Phase | Action | Command Example | Expected Result |
|---|---|---|---|
| RED | Write failing test | cargo test test_name | FAIL (feature missing) |
| Verify RED | Confirm correct failure | Check error message | "function not found" or assertion fails |
| GREEN | Write minimal code | Implement feature | Test passes |
| Verify GREEN | All tests pass | cargo test | All green, no warnings |
| REFACTOR | Clean up code | Improve while green | Tests still pass |
Iron Law: NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
</quick_reference>
<when_to_use> Always use for:
Ask your human partner for exceptions:
Thinking "skip TDD just this once"? Stop. That's rationalization. </when_to_use>
<the_process>
Write one minimal test showing what should happen.
Requirements:
See resources/language-examples.md for Rust, Swift, TypeScript examples.
MANDATORY. Never skip.
Run the test and confirm:
If test passes: You're testing existing behavior. Fix the test. If test errors: Fix syntax error, re-run until it fails correctly.
Write simplest code to pass the test. Nothing more.
Key principle: Don't add features the test doesn't require. Don't refactor other code. Don't "improve" beyond the test.
MANDATORY.
Run tests and confirm:
If test fails: Fix code, not test. If other tests fail: Fix now before proceeding.
Only after green:
Keep tests green. Don't add behavior.
Next failing test for next feature.
</the_process>
Developer writes implementation first, then adds test that passes immediately
// Code written FIRST
def validate_email(email):
return "@" in email # Bug: accepts "@@"
// Test written AFTER
def test_validate_email():
assert validate_email("[email protected]") # Passes immediately!
// Missing edge case: assert not validate_email("@@")
<why_it_fails> When test passes immediately:
Tests written after verify remembered cases, not required behavior. </why_it_fails>
**TDD approach:**def test_validate_email():
assert validate_email("[email protected]") # Will fail - function doesn't exist
assert not validate_email("@@") # Edge case up front
NameError: function 'validate_email' is not defined
def validate_email(email):
return "@" in email and email.count("@") == 1
Result: Test failed first, proving it works. Edge case discovered during test writing, not in production.
Developer has already written 3 hours of code without tests. Wants to keep it as "reference" while writing tests.
// 200 lines of untested code exists
// Developer thinks: "I'll keep this and write tests that match it"
// Or: "I'll use it as reference to speed up TDD"
<why_it_fails> Keeping code as "reference":
Result: All the problems of test-after, none of the benefits of TDD. </why_it_fails>
**Delete it. Completely.**git stash # Or delete the file
Then start TDD:
Why delete:
What you gain:
// Test attempt:
func testUserServiceCreatesAccount() {
// Need to mock database, email service, payment gateway, logger...
// This is getting complicated, maybe I should just implement first
}
<why_it_fails> "Test is hard" is valuable signal:
Implementing first ignores this signal:
Hard to test? Simplify the interface:
// Instead of:
class UserService {
init(db: Database, email: EmailService, payments: PaymentGateway, logger: Logger) { }
func createAccount(email: String, password: String, paymentToken: String) throws { }
}
// Make testable:
class UserService {
func createAccount(request: CreateAccountRequest) -> Result<Account, Error> {
// Dependencies injected through request or passed separately
}
}
Test becomes simple:
func testCreatesAccountFromRequest() {
let service = UserService()
let request = CreateAccountRequest(email: "[email protected]")
let result = service.createAccount(request: request)
XCTAssertEqual(result.email, "[email protected]")
}
TDD forces good design. If test is hard, fix design before implementing.
<critical_rules>
Write code before test? → Delete it. Start over.
Test passes immediately? → Not TDD. Fix the test or delete the code.
Can't explain why test failed? → Fix until failure makes sense.
Want to skip "just this once"? → That's rationalization. Stop.
All of these mean: Stop, follow TDD:
</critical_rules>
<verification_checklist>
Before marking work complete:
Can't check all boxes? You skipped TDD. Start over.
</verification_checklist>
This skill calls:
This skill is called by:
Agents used:
Detailed language-specific examples:
When stuck:
npx claudepluginhub dpolishuk/xpowers --plugin xpowersEnforces strict RED-GREEN-REFACTOR TDD cycle for features and bug fixes: write minimal failing test first with verification, minimal code to pass, refactor while green.
Enforces strict Test-Driven Development (TDD): write failing test first for features, bug fixes, refactors before any production code.
Guides test-driven development: write a failing test first, then minimal code to pass, then refactor. Use before implementing any feature or bugfix to ensure correct behavior.