TDD Red-Green Workflow
I'll guide you through true Test-Driven Development with strict RED → GREEN → REFACTOR cycle enforcement.
TDD Philosophy (Based on obra/superpowers):
- Write failing test FIRST (RED)
- Write minimum code to pass (GREEN)
- Refactor while keeping tests green
- YAGNI: You Aren't Gonna Need It
- DRY: Don't Repeat Yourself
Phase 1: Verify TDD Prerequisites
First, let me check your test setup:
# Check for cached framework detection (70% savings on cache hit)
CACHE_FILE=".claude/cache/test/framework-config.json"
CACHE_VALIDITY=86400 # 24 hours
if [ -f "$CACHE_FILE" ]; then
LAST_MODIFIED=$(stat -c %Y "$CACHE_FILE" 2>/dev/null || stat -f %m "$CACHE_FILE" 2>/dev/null)
CURRENT_TIME=$(date +%s)
AGE=$((CURRENT_TIME - LAST_MODIFIED))
if [ $AGE -lt $CACHE_VALIDITY ]; then
FRAMEWORK=$(jq -r '.framework' "$CACHE_FILE" 2>/dev/null)
if [ -n "$FRAMEWORK" ] && [ "$FRAMEWORK" != "null" ]; then
echo "✓ Using cached framework: $FRAMEWORK"
# Skip expensive detection, saves 70% tokens
fi
fi
fi
# Detect test framework (token-efficient with Grep)
detect_test_framework() {
if [ -f "package.json" ]; then
if grep -q "\"jest\"" package.json; then
echo "jest"
elif grep -q "\"vitest\"" package.json; then
echo "vitest"
elif grep -q "\"mocha\"" package.json; then
echo "mocha"
fi
elif [ -f "requirements.txt" ] || [ -f "setup.py" ]; then
if grep -q "pytest" requirements.txt setup.py 2>/dev/null; then
echo "pytest"
elif grep -q "unittest" requirements.txt setup.py 2>/dev/null; then
echo "unittest"
fi
elif [ -f "go.mod" ]; then
echo "go test"
fi
}
FRAMEWORK=$(detect_test_framework)
if [ -z "$FRAMEWORK" ]; then
echo "❌ No test framework detected"
echo "Please install a test framework:"
echo " JavaScript/TypeScript: npm install --save-dev jest"
echo " Python: pip install pytest"
echo " Go: Native 'go test' support"
exit 1
fi
echo "✓ Test framework detected: $FRAMEWORK"
Phase 2: TDD Workflow Guidance
I'll guide you through the RED-GREEN-REFACTOR cycle:
Step 1: RED - Write Failing Test First
Your task: Write a test that describes what you want to build.
echo "=== STEP 1: RED (Write Failing Test) ==="
echo ""
echo "Before writing any implementation code, you must:"
echo "1. Write a test that describes the desired behavior"
echo "2. Run the test to confirm it FAILS"
echo "3. Understand WHY it fails (no implementation exists)"
echo ""
echo "Example test structure:"
case $FRAMEWORK in
jest|vitest)
cat << 'EOF'
describe('UserAuth', () => {
test('should authenticate valid user credentials', () => {
const auth = new UserAuth();
const result = auth.login('user@example.com', 'password123');
expect(result.success).toBe(true);
expect(result.token).toBeDefined();
});
});
EOF
;;
pytest)
cat << 'EOF'
def test_user_authentication():
auth = UserAuth()
result = auth.login('user@example.com', 'password123')
assert result['success'] is True
assert 'token' in result
EOF
;;
esac
echo "After writing your test, run it to see it FAIL:"
case $FRAMEWORK in
jest) echo " npm test" ;;
vitest) echo " npm run test" ;;
pytest) echo " pytest" ;;
"go test") echo " go test ./..." ;;
esac
Step 2: Verify RED State
echo ""
echo "=== Verification Checkpoint ==="
read -p "Did your test FAIL as expected? (yes/no): " test_failed
if [ "$test_failed" != "yes" ]; then
echo ""
echo "⚠️ TDD Violation: Test should FAIL first!"
echo ""
echo "Common mistakes:"
echo " - Test passes immediately (implementation already exists)"
echo " - Test has syntax errors (doesn't run at all)"
echo " - Test doesn't actually test the behavior"
echo ""
echo "Fix: Ensure test runs and fails for the right reason"
exit 1
fi
echo "✓ RED phase complete: Test is failing"
Step 3: GREEN - Write Minimum Code
echo ""
echo "=== STEP 2: GREEN (Make Test Pass) ==="
echo ""
echo "Now write the MINIMUM code to make the test pass:"
echo " - Don't over-engineer"
echo " - Don't add extra features"
echo " - Don't optimize prematurely"
echo " - Just make the test green"
echo ""
echo "YAGNI Principle: You Aren't Gonna Need It"
echo " - No 'what if' code"
echo " - No 'future-proofing'"
echo " - Only what's needed NOW"
Step 4: Verify GREEN State
echo ""
read -p "Have you written the implementation? (yes/no): " impl_written
if [ "$impl_written" = "yes" ]; then
echo ""
echo "Run tests to verify GREEN state:"
# Run tests based on framework
case $FRAMEWORK in
jest|vitest)
npm test
TEST_RESULT=$?
;;
pytest)
pytest
TEST_RESULT=$?
;;
"go test")
go test ./...
TEST_RESULT=$?
;;
esac
if [ $TEST_RESULT -eq 0 ]; then
echo ""
echo "✅ GREEN phase complete: Test is passing!"
else
echo ""
echo "❌ Tests still failing. Continue implementing until green."
exit 1
fi
fi
Step 5: REFACTOR - Clean Up
echo ""
echo "=== STEP 3: REFACTOR (Clean Code) ==="
echo ""
echo "Now that tests are green, you can refactor:"
echo " - Extract functions/methods"
echo " - Remove duplication (DRY)"
echo " - Improve naming"
echo " - Simplify logic"
echo ""
echo "⚠️ CRITICAL: Run tests after each refactoring step!"
echo ""
echo "Safe refactoring loop:"
echo " 1. Refactor one small thing"
echo " 2. Run tests (should stay green)"
echo " 3. If green, commit"
echo " 4. Repeat"
Phase 3: TDD Cycle Monitoring
I'll help verify you're following true TDD:
# Check for common TDD violations
check_tdd_violations() {
echo ""
echo "=== TDD Health Check ==="
# Check if tests exist for recent code
RECENT_SOURCE_FILES=$(git log --name-only --pretty=format: --since="1 day ago" | grep -E '\.(ts|js|py|go)$' | grep -v test | sort -u)
if [ ! -z "$RECENT_SOURCE_FILES" ]; then
echo ""
echo "Recent source files modified:"
echo "$RECENT_SOURCE_FILES" | sed 's/^/ /'
echo ""
echo "Checking for corresponding tests..."
for source_file in $RECENT_SOURCE_FILES; do
# Look for test file
test_file=$(echo "$source_file" | sed 's/\.\([^.]*\)$/.test.\1/')
if [ ! -f "$test_file" ]; then
echo " ⚠️ No test found for: $source_file"
else
echo " ✓ Test exists: $test_file"
fi
done
fi
# Check test-to-code ratio
SOURCE_LINES=$(find . -name "*.ts" -o -name "*.js" -o -name "*.py" | grep -v test | xargs wc -l 2>/dev/null | tail -1 | awk '{print $1}')
TEST_LINES=$(find . -name "*.test.*" -o -name "*_test.*" | xargs wc -l 2>/dev/null | tail -1 | awk '{print $1}')
if [ ! -z "$SOURCE_LINES" ] && [ "$SOURCE_LINES" -gt 0 ]; then
RATIO=$((TEST_LINES * 100 / SOURCE_LINES))
echo ""
echo "Test coverage ratio: ${RATIO}%"
if [ $RATIO -lt 50 ]; then
echo " ⚠️ Low test coverage (target: 80%+)"
elif [ $RATIO -lt 80 ]; then
echo " ⚙️ Moderate test coverage (target: 80%+)"
else
echo " ✅ Good test coverage!"
fi
fi
}
check_tdd_violations
TDD Best Practices
Anti-Patterns to Avoid:
- Writing implementation before test
- Writing comprehensive tests after code is done
- Skipping the RED phase
- Testing implementation details instead of behavior
- Writing tests that always pass
TDD Benefits:
- Confidence in refactoring
- Better design through testability
- Living documentation
- Fewer bugs in production
- Faster debugging
Integration Points
This skill works well with:
/test- Run your TDD tests/refactor- Safe refactoring with test coverage/commit- Commit after each successful cycle
Next Steps
echo ""
echo "=== TDD Workflow Summary ==="
echo ""
echo "1. 🔴 RED: Write failing test"
echo "2. ✅ GREEN: Make test pass (minimum code)"
echo "3. 🔧 REFACTOR: Clean up while keeping tests green"
echo ""
echo "Repeat this cycle for each new feature or change!"
echo ""
echo "Suggested workflow:"
echo " 1. Start: /tdd-red-green (this skill)"
echo " 2. Develop: Follow RED-GREEN-REFACTOR"
echo " 3. Test: /test"
echo " 4. Commit: /commit"
Important: This skill enforces methodology, not automation. True TDD requires discipline and practice. Use this skill as a guide and checklist for each development cycle.
Credits: TDD methodology based on obra/superpowers RED/GREEN/REFACTOR workflow and YAGNI/DRY principles.
Token Optimization
Expected range: 800–2,000 tokens (initial), 100 tokens (no test framework)
Caching: Caches test framework config in .claude/cache/test/framework-config.json for 7 days. Invalidated when package.json changes.
Early exit: Returns immediately if no test framework is found in the project.
Patterns used: Grep-before-Read, early exit, git diff scope default, caching