Test-Driven Development

SkillAI & models

Write tests before code using RED-GREEN-REFACTOR cycle

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Test-Driven Development skill

What this skill tells your AI

The instructions your AI receives, as published by fdhhhdjd/class-ai-agent in .claude/skills/tdd/SKILL.md and read by ahel’s review.

Overview

TDD transforms testing from an afterthought into the foundation of development. Tests are proof that code works correctly.

When to Invoke

  • Writing new features
  • Fixing bugs (Prove-It pattern)
  • When asked to write tests
  • Before any implementation work

Core Cycle: RED-GREEN-REFACTOR

RED Phase

Write a test that describes expected behavior. It must fail.

describe('calculateDiscount', () => {
  it('should apply 10% discount for orders over $100', () => {
    const result = calculateDiscount(150);
    expect(result).toBe(15);
  });
});

Run: npm test → Should FAIL

GREEN Phase

Write minimal code to pass the test. No extras.

function calculateDiscount(amount) {
  if (amount > 100) return amount * 0.1;
  return 0;
}

Run: npm test → Should PASS

REFACTOR Phase

Improve code while keeping tests green.

const DISCOUNT_THRESHOLD = 100;
const DISCOUNT_RATE = 0.1;

function calculateDiscount(amount) {
  if (amount <= DISCOUNT_THRESHOLD) return 0;
  return amount * DISCOUNT_RATE;
}

Run: npm test → Should still PASS


Prove-It Pattern (Bug Fixes)

Step 1: Write Failing Test

it('should handle empty cart without error (bug #456)', () => {
  const cart = new Cart([]);
  expect(() => cart.getTotal()).not.toThrow();
  expect(cart.getTotal()).toBe(0);
});

Step 2: Verify Failure

Run test → Confirms bug exists

Step 3: Fix Bug

getTotal() {
  if (this.items.length === 0) return 0;  // Fix
  return this.items.reduce((sum, item) => sum + item.price, 0);
}

Step 4: Verify Pass

Run test → Confirms fix works

Step 5: Run Full Suite

npm test  # No regressions

Test Pyramid

         ┌─────────┐
         │   E2E   │  5%  — Critical user flows
         │  Tests  │       Full system, minutes
         ├─────────┤
         │ Integr. │  15% — API + DB interactions
         │  Tests  │       Seconds
         ├─────────┤
         │  Unit   │  80% — Pure logic
         │  Tests  │       Milliseconds
         └─────────┘

Test Structure: AAA Pattern

it('should calculate tax for California', () => {
  // Arrange — Setup
  const order = createOrder({ state: 'CA', subtotal: 100 });

  // Act — Execute
  const tax = calculateTax(order);

  // Assert — Verify
  expect(tax).toBe(7.25);
});

DAMP > DRY in Tests

Tests should be Descriptive And Meaningful Phrases.

// ✅ DAMP — Self-contained and clear
it('should reject password without uppercase letter', () => {
  const result = validatePassword('lowercase123!');

  expect(result.valid).toBe(false);
  expect(result.errors).toContain('Must contain uppercase letter');
});

// ❌ Too DRY — Requires reading shared context
it('should reject invalid password', () => {
  expect(validate(INVALID_PASSWORD_NO_UPPER)).toBe(false);
});

Test Doubles (Preference Order)

  1. Real implementations — Best, but may be slow
  2. Fakes — In-memory DB, simplified implementations
  3. Stubs — Return canned responses
  4. Mocks — Verify interactions (use sparingly)
// ✅ Prefer: Real or fake
const db = createTestDatabase();
const user = await userService.create(db, userData);

// ⚠️ Use sparingly: Mocks
const mockDb = { create: vi.fn().mockResolvedValue(user) };

Naming Conventions

// Pattern: should [expected behavior] when [condition]

// ✅ Good
'should return empty array when no users exist'
'should throw ValidationError when email is invalid'
'should send welcome email after registration'

// ❌ Bad
'works correctly'
'test user creation'
'handles error'

Anti-Patterns

PatternProblemSolution
Testing internalsBreaks on refactorTest behavior, not implementation
Flaky testsErodes trustUse deterministic data
Over-mockingFalse confidencePrefer real implementations
Snapshot abuseLarge diffs ignoredUse sparingly
Shared mutable stateTests affect each otherReset in beforeEach
Testing frameworksWasted effortOnly test your code

Verification Checklist

  • All new code has tests
  • Bug fixes have reproduction tests
  • Tests describe behavior (readable names)
  • No skipped tests
  • Coverage maintained/improved
  • Full suite passes

Signals

GitHub stars
264
Forks
166
Last commit
Apr 2026
Advanced
Catalog kind
skill
Gateway key
test-driven-development-fdhhhdjd
Source
github.com/fdhhhdjd/class-ai-agent