/tdd-london-chicago
Apply London (mock-based) and Chicago (state-based) TDD schools. Use when practicing test-driven development or choosing testing style for your context.
$ npx -y skills add proffesor-for-testing/agentic-qe --skill tdd-london-chicago --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/tdd-london-chicago
Context preview
The summary Claude sees to decide when to auto-load this skill.
Apply London (mock-based) and Chicago (state-based) TDD schools. Use when practicing test-driven development or choosing testing style for your context.
SKILL.md
tdd-london-chicago.SKILL.mdname: tdd-london-chicago
description: "Apply London (mock-based) and Chicago (state-based) TDD schools. Use when practicing test-driven development or choosing testing style for your context."
category: development-practices
priority: high
tokenEstimate: 1100
agents: [qe-test-generator, qe-test-implementer, qe-test-refactorer]
implementation_status: optimized
optimization_version: 1.0
last_optimized: 2025-12-02
dependencies: []
quick_reference_card: true
tags: [tdd, testing, london-school, chicago-school, red-green-refactor, mocks]
trust_tier: 2
validation:
schema_path: schemas/output.json
validator_path: scripts/validate-config.json
Test-Driven Development: London & Chicago Schools
<default_to_action> When implementing TDD or choosing testing style: 1. IDENTIFY code type: domain logic → Chicago, external deps → London 2. WRITE failing test first (Red phase) 3. IMPLEMENT minimal code to pass (Green phase) 4. REFACTOR while keeping tests green (Refactor phase) 5. 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
</default_to_action>
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
| Phase | Action | Discipline | |-------|--------|------------| | **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
| Aspect | Chicago (Classicist) | London (Mockist) | |--------|---------------------|------------------| | 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)
---
Mixed Approach (Recommended)
// 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"Read more
name: tdd-london-chicago description: "Apply London (mock-based) and Chicago (state-based) TDD schools. Use when practicing test-driven development or choosing testing style for your context." category: development-practices priority: high tokenEstimate: 1100 agents: [qe-test-generator, qe-test-implementer, qe-test-refactorer] implementation_status: optimized optimization_version: 1.0 last_optimized: 2025-12-02 dependencies: [] quick_reference_card: true tags: [tdd, testing, london-school, chicago-school, red-green-refactor, mocks] trust_tier: 2 validation: schema_path: schemas/output.json validator_path: scripts/validate-config.json
Test-Driven Development: London & Chicago Schools
<default_to_action> When implementing TDD or choosing testing style: 1. IDENTIFY code type: domain logic → Chicago, external deps → London 2. WRITE failing test first (Red phase) 3. IMPLEMENT minimal code to pass (Green phase) 4. REFACTOR while keeping tests green (Refactor phase) 5. 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
</default_to_action>
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
| Phase | Action | Discipline | |-------|--------|------------| | **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
| Aspect | Chicago (Classicist) | London (Mockist) | |--------|---------------------|------------------| | 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)
---
Mixed Approach (Recommended)
// 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"AI-powered quality engineering agents that generate tests, find coverage gaps, detect flaky tests, and learn your codebase patterns — across 11 coding agent platforms.
Repo: proffesor-for-testing/agentic-qe
Other skills on agentic-qe.
- /a11y-ally
Use when running comprehensive WCAG accessibility audits with axe-core + pa11y + Lighthouse, generating context-aware remediation, or testing video accessibility. Supports 3-tier browser cascade with graceful degradation.
Open skill - /accessibility-testing
WCAG 2.2 compliance testing, screen reader validation, and inclusive design verification. Use when ensuring legal compliance (ADA, Section 508), testing for disabilities, or building accessible applications for 1 billion disabled users globally.
Open skill - /agentdb-advanced
Master advanced AgentDB features including QUIC synchronization, multi-database management, custom distance metrics, hybrid search, and distributed systems integration. Use when building distributed AI systems, multi-agent coordination, or advanced vector search applications.
Open skill - /agentdb-learning
Create and train AI learning plugins with AgentDB's 9 reinforcement learning algorithms. Includes Decision Transformer, Q-Learning, SARSA, Actor-Critic, and more. Use when building self-learning agents, implementing RL, or optimizing agent behavior through experience.
Open skill - /agentdb-memory-patterns
Implement persistent memory patterns for AI agents using AgentDB. Includes session memory, long-term storage, pattern learning, and context management. Use when building stateful agents, chat systems, or intelligent assistants.
Open skill - /agentdb-optimization
Optimize AgentDB performance with quantization (4-32x memory reduction), HNSW indexing (150x faster search), caching, and batch operations. Use when optimizing memory usage, improving search speed, or scaling to millions of vectors.
Open skill

