tdd-london-chicago

安装量: 59
排名: #12607

安装

npx skills add https://github.com/proffesor-for-testing/agentic-qe --skill tdd-london-chicago

When implementing TDD or choosing testing style:

  • IDENTIFY code type: domain logic → Chicago, external deps → London

  • WRITE failing test first (Red phase)

  • IMPLEMENT minimal code to pass (Green phase)

  • REFACTOR while keeping tests green (Refactor phase)

  • REPEAT cycle for next functionality

Quick Style Selection:

  • Pure functions/calculations → Chicago (real objects, state verification)

  • Controllers/services with deps → London (mocks, interaction verification)

  • Value objects → Chicago (test final state)

  • API integrations → London (mock external services)

  • Mix both in practice (London for controllers, Chicago for domain)

Critical Success Factors:

  • Tests drive design, not just verify it

  • Make tests fail first to ensure they test something

  • Write minimal code - no features beyond what's tested

Quick Reference Card

When to Use

  • Starting new feature with test-first approach

  • Refactoring legacy code with test coverage

  • Teaching TDD practices to team

  • Choosing between mocking vs real objects

TDD Cycle

| Red | Write failing test | Verify it fails, check message is clear

| Green | Minimal code to pass | No extra features, don't refactor

| Refactor | Improve structure | Keep tests passing, no new functionality

School Comparison

| Collaborators | Real objects | Mocks/stubs

| Verification | State (assert outcomes) | Interaction (assert calls)

| Isolation | Lower (integrated) | Higher (unit only)

| Refactoring | Easier | Harder (mocks break)

| Design feedback | Emerges from use | Explicit from start

Agent Coordination

  • qe-test-generator: Generate tests in both schools

  • qe-test-implementer: Implement minimal code (Green)

  • qe-test-refactorer: Safe refactoring (Refactor)

Chicago School (State-Based)

Philosophy: Test observable behavior through public API. Keep tests close to consumer usage.

// State verification - test final outcome
describe('Order', () => {
  it('calculates total with tax', () => {
    const order = new Order();
    order.addItem(new Product('Widget', 10.00), 2);
    order.addItem(new Product('Gadget', 15.00), 1);

    expect(order.totalWithTax(0.10)).toBe(38.50);
  });
});

When Chicago Shines:

  • Domain logic with clear state

  • Algorithms and calculations

  • Value objects (Money, Email)

  • Simple collaborations

  • Learning new domain

London School (Mock-Based)

Philosophy: Test each unit in isolation. Focus on how objects collaborate.

// Interaction verification - test method calls
describe('Order', () => {
  it('delegates tax calculation', () => {
    const taxCalculator = {
      calculateTax: jest.fn().mockReturnValue(3.50)
    };
    const order = new Order(taxCalculator);
    order.addItem({ price: 10 }, 2);

    order.totalWithTax();

    expect(taxCalculator.calculateTax).toHaveBeenCalledWith(20.00);
  });
});

When London Shines:

  • External integrations (DB, APIs)

  • Command patterns with side effects

  • Complex workflows

  • Slow operations (network, I/O)

// London for controller (external deps)
describe('OrderController', () => {
  it('creates order and sends confirmation', async () => {
    const orderService = { create: jest.fn().mockResolvedValue({ id: 123 }) };
    const emailService = { send: jest.fn() };

    const controller = new OrderController(orderService, emailService);
    await controller.placeOrder(orderData);

    expect(orderService.create).toHaveBeenCalledWith(orderData);
    expect(emailService.send).toHaveBeenCalled();
  });
});

// Chicago for domain logic
describe('OrderService', () => {
  it('applies discount when threshold met', () => {
    const service = new OrderService();
    const order = service.create({ items: [...], total: 150 });

    expect(order.discount).toBe(15); // 10% off > $100
  });
});

Common Pitfalls

❌ Over-Mocking (London)

// BAD - mocking everything
const product = { getName: jest.fn(), getPrice: jest.fn() };

Better: Only mock external dependencies.

❌ Mocking Internals

// BAD - testing private methods
expect(order._calculateSubtotal).toHaveBeenCalled();

Better: Test public behavior only.

❌ Test Pain = Design Pain

  • Need many mocks? → Too many dependencies

  • Hard to set up? → Constructor does too much

  • Can't test without database? → Coupling issue

Agent-Assisted TDD

// Agent generates tests in both schools
await Task("Generate Tests", {
  style: 'chicago',      // or 'london'
  target: 'src/domain/Order.ts',
  focus: 'state-verification'  // or 'collaboration-patterns'
}, "qe-test-generator");

// Agent-human ping-pong TDD
// Human writes test concept
const testIdea = "Order applies 10% discount when total > $100";

// Agent generates formal failing test (Red)
await Task("Create Failing Test", testIdea, "qe-test-generator");

// Human writes minimal code (Green)

// Agent suggests refactorings
await Task("Suggest Refactorings", { preserveTests: true }, "qe-test-refactorer");

Agent Coordination Hints

Memory Namespace

aqe/tdd/
├── test-plan/*        - TDD session plans
├── red-phase/*        - Failing tests generated
├── green-phase/*      - Implementation code
└── refactor-phase/*   - Refactoring suggestions

Fleet Coordination

const tddFleet = await FleetManager.coordinate({
  workflow: 'red-green-refactor',
  agents: {
    testGenerator: 'qe-test-generator',
    testExecutor: 'qe-test-executor',
    qualityAnalyzer: 'qe-quality-analyzer'
  },
  mode: 'sequential'
});

Remember

Chicago: Test state, use real objects, refactor freely London: Test interactions, mock dependencies, design interfaces first Both: Write the test first, make it pass, refactor

Neither is "right." Choose based on context. Mix as needed. Goal: well-designed, tested code.

With Agents: Agents excel at generating tests, validating green phase, and suggesting refactorings. Use agents to maintain TDD discipline while humans focus on design decisions.

返回排行榜