# Tdd Enforcer

> This skill should be used when "write tests first", "do TDD", "test driven development", "write tests before code", "test this feature", "add test coverage", "make sure this is tested", "write unit tests", "add integration tests".

- Skill: `kwokyc/tdd-enforcer` (Agent Skill)
- Install (CLI): `npx skillmds@latest add kwokyc/tdd-enforcer`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kwokyc/tdd-enforcer/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: KwokYC (https://skillmd.com/u/kwokyc)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/kwokyc/tdd-enforcer

---


# TDD Enforcer

Enforce test-driven development. Write tests FIRST, then write the minimum code to make them pass.

## The TDD Cycle

```
RED → GREEN → REFACTOR

1. RED:    Write a failing test that defines the desired behavior
2. GREEN:  Write the minimum code to make the test pass
3. REFACTOR: Clean up while keeping tests green
```

## When to Activate

- Implementing a new feature
- Fixing a bug (write a failing test first that reproduces it)
- Refactoring existing code (ensure tests exist before touching it)
- User explicitly asks for tests or TDD

## Core Rules

### Rule 1: Test Before Code

Always write the test first. Never write implementation without a corresponding test.

```
User: "Add a function that validates email format"

❌ WRONG: Write validate_email() first, then add tests
✅ RIGHT:
  1. Write test_validate_email_rejects_invalid() → fails
  2. Write test_validate_email_accepts_valid() → fails
  3. Write validate_email() → tests pass
  4. Refactor if needed
```

### Rule 2: One Behavior Per Test

Each test verifies exactly one behavior.

```python
# ❌ Testing multiple things
def test_user_creation():
    user = create_user("Alice", "alice@example.com")
    assert user.name == "Alice"
    assert user.email == "alice@example.com"
    assert user.is_active == True
    send_welcome_email(user)  # Side effect!
    assert user.welcome_sent == True

# ✅ Separate tests
def test_create_user_sets_name():
    user = create_user("Alice", "alice@example.com")
    assert user.name == "Alice"

def test_create_user_sets_email():
    user = create_user("Alice", "alice@example.com")
    assert user.email == "alice@example.com"

def test_create_user_is_active_by_default():
    user = create_user("Alice", "alice@example.com")
    assert user.is_active == True
```

### Rule 3: AAA Pattern

Every test follows Arrange → Act → Assert.

```typescript
// ✅ Clear AAA structure
test("should apply discount to orders over $100", () => {
  // Arrange
  const order = new Order();
  order.addItem({ price: 150, quantity: 1 });

  // Act
  const total = order.calculateTotal();

  // Assert
  expect(total).toBe(135); // 10% discount applied
});
```

### Rule 4: Test Names Describe Behavior

```
❌ test_user_1
❌ test_validation
❌ test_error

✅ test_create_user_rejects_empty_name
✅ test_validate_email_rejects_missing_at_symbol
✅ test_checkout_returns_400_when_cart_is_empty
```

### Rule 5: Test Edge Cases

For every function, test:

```markdown
- Happy path (normal expected input)
- Empty input (empty string, empty array, null)
- Boundary values (0, -1, max_int)
- Invalid input (wrong type, malformed data)
- Concurrent access (if applicable)
```

```python
def test_parse_age():
    assert parse_age("25") == 25        # happy path
    assert parse_age("0") == 0          # boundary
    assert parse_age("") is None        # empty
    assert parse_age("abc") is None     # invalid
    assert parse_age("-1") is None      # negative
    assert parse_age("999") == 999      # large
```

## Test Structure Templates

### Unit Test (Python / pytest)

```python
import pytest

class TestFeatureName:
    """Tests for feature_name function."""

    def test_expected_behavior_happy_path(self):
        result = feature_name(valid_input)
        assert result == expected_output

    def test_edge_case_empty_input(self):
        result = feature_name("")
        assert result is None

    def test_invalid_input_raises_error(self):
        with pytest.raises(ValueError, match="specific error message"):
            feature_name(invalid_input)
```

### Unit Test (TypeScript / Vitest)

```typescript
import { describe, it, expect } from "vitest";

describe("featureName", () => {
  it("should return expected output for valid input", () => {
    expect(featureName(validInput)).toBe(expectedOutput);
  });

  it("should return null for empty input", () => {
    expect(featureName("")).toBeNull();
  });

  it("should throw for invalid input", () => {
    expect(() => featureName(invalidInput)).toThrow("specific error");
  });
});
```

### Integration Test

```python
def test_user_registration_flow():
    """Test the complete user registration process."""
    # Arrange
    client = TestClient(app)
    payload = {"name": "Alice", "email": "alice@test.com", "password": "secure123"}

    # Act
    response = client.post("/api/register", json=payload)

    # Assert
    assert response.status_code == 201
    data = response.json()
    assert data["name"] == "Alice"
    assert "password" not in data  # Never expose password

    # Verify side effect
    user = db.query(User).filter_by(email="alice@test.com").first()
    assert user is not None
    assert bcrypt.checkpw("secure123", user.password_hash)
```

## Bug Fix TDD Process

When fixing a bug, always follow this sequence:

```
1. REPRODUCE: Write a test that fails with the bug
2. CONFIRM: Run test, see it fail (RED)
3. FIX: Write minimum code to make test pass
4. VERIFY: Run test, see it pass (GREEN)
5. REGRESSION: Run full test suite, ensure nothing broke
```

```
❌ WRONG: "I found the bug, let me fix it" (fixes without test)
✅ RIGHT: "I'll write a test that reproduces this bug first"
```

## Coverage Guidelines

```
Target coverage by code type:
- Business logic:    90-100%
- API endpoints:     80-90%
- Utility functions: 90-100%
- UI components:     60-80%
- Configuration:     Skip (test via integration)
- Glue code:         Skip (covered by integration tests)
```

Do NOT chase 100% coverage. Focus on meaningful tests for critical paths.

## Anti-Patterns

### Testing Implementation Details
```
❌ Testing internal state: expect(component.state.counter).toBe(1)
✅ Testing behavior: expect(screen.getByText("Count: 1")).toBeInTheDocument()
```

### Mocking Everything
```
❌ Mock database, mock API, mock filesystem, mock time
✅ Use real objects where possible, mock only external services
```

### Brittle Assertions
```
❌ expect(result).toBe("exactly this string with no flexibility")
✅ expect(result).toContain("key phrase")
✅ expect(result).toMatch(/^\d{4}-\d{2}-\d{2}$/)  // date pattern
```

### Test Interdependence
```
❌ test_b depends on test_a running first
✅ Each test is fully independent, can run in any order
```

## Quick Reference

| Situation | Action |
|-----------|--------|
| New feature | Write failing test first |
| Bug fix | Write reproducing test first |
| Refactor | Ensure tests exist first |
| No tests exist | Write tests before changing code |
| Test is flaky | Fix or delete it, never ignore it |

