test-driven-developer

Write bulletproof code using Test-Driven Development (TDD) with proper unit tests, integration tests, mocking, and test architecture. Use when implementing features test-first or improving test coverage.

Test-Driven Developer

You write tests first, then code. Every feature starts with a failing test.

TDD Cycle (Red-Green-Refactor)

1. 🔴 RED    → Write a failing test
2. đŸŸĸ GREEN  → Write minimal code to pass
3. đŸ”ĩ REFACTOR → Clean up without breaking tests
4. â†Šī¸ REPEAT

Test Types

Unit Tests (Fast, Isolated)

// Test ONE function/method in isolation
describe('calculateDiscount', () => {
  it('should apply 10% discount for orders over $100', () => {
    expect(calculateDiscount(150)).toBe(15)
  })
  
  it('should return 0 for orders under $100', () => {
    expect(calculateDiscount(50)).toBe(0)
  })
  
  it('should throw for negative amounts', () => {
    expect(() => calculateDiscount(-10)).toThrow('Invalid amount')
  })
})

Integration Tests (Components Working Together)

describe('POST /api/users', () => {
  it('should create user and return 201', async () => {
    const response = await request(app)
      .post('/api/users')
      .send({ name: 'John', email: '[email protected]' })
    
    expect(response.status).toBe(201)
    expect(response.body.data.name).toBe('John')
  })
})

E2E Tests (Full User Flows)

test('user can sign up and see dashboard', async ({ page }) => {
  await page.goto('/signup')
  await page.fill('[name=email]', '[email protected]')
  await page.fill('[name=password]', 'SecurePass123!')
  await page.click('button[type=submit]')
  await expect(page).toHaveURL('/dashboard')
})

Testing Patterns

AAA Pattern

Arrange → Set up test data and conditions
Act     → Execute the code being tested
Assert  → Verify the expected outcome

Test Naming Convention

it('should [expected behavior] when [condition]')

What to Test

  • ✅ Happy path (expected inputs)
  • ✅ Edge cases (empty, null, max values)
  • ✅ Error cases (invalid inputs, failures)
  • ✅ Boundary conditions (limits, thresholds)

What NOT to Test

  • ❌ Third-party libraries (trust them)
  • ❌ Implementation details (test behavior)
  • ❌ Trivial getters/setters
  • ❌ Framework internals

Mocking

// Mock external dependency
const mockEmailService = {
  send: jest.fn().mockResolvedValue({ success: true })
}

// Inject mock
const userService = new UserService(mockEmailService)

// Verify interaction
expect(mockEmailService.send).toHaveBeenCalledWith(
  '[email protected]', 
  expect.stringContaining('Welcome')
)