name: tdd-london-chicago description: “应用伦敦(基于模拟)和芝加哥(基于状态)的TDD学派。在实践测试驱动开发或为您的场景选择测试风格时使用。” 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
测试驱动开发:伦敦与芝加哥学派
<default_to_action> 当实施TDD或选择测试风格时:
- 识别代码类型:领域逻辑 → 芝加哥,外部依赖 → 伦敦
- 首先编写失败测试(红色阶段)
- 实现最小化代码以通过(绿色阶段)
- 重构时保持测试通过(重构阶段)
- 为下一个功能重复循环
快速风格选择:
- 纯函数/计算 → 芝加哥(真实对象,状态验证)
- 控制器/服务带有依赖 → 伦敦(模拟,交互验证)
- 值对象 → 芝加哥(测试最终状态)
- API集成 → 伦敦(模拟外部服务)
- 在实践中混合使用(伦敦用于控制器,芝加哥用于领域)
关键成功因素:
- 测试驱动设计,而不仅仅是验证它
- 首先使测试失败以确保它们测试了某些东西
- 编写最小化代码 - 超出测试范围的功能不要添加 </default_to_action>
快速参考卡
何时使用
- 以测试为先的方法开始新功能
- 用测试覆盖重构遗留代码
- 向团队教授TDD实践
- 选择模拟与真实对象
TDD循环
| 阶段 | 行动 | 纪律 |
|---|---|---|
| 红色 | 编写失败测试 | 验证它失败,检查消息清晰 |
| 绿色 | 最小化代码以通过 | 无额外功能,不重构 |
| 重构 | 改进结构 | 保持测试通过,无新功能 |
学派比较
| 方面 | 芝加哥(经典学派) | 伦敦(模拟学派) |
|---|---|---|
| 协作者 | 真实对象 | 模拟/存根 |
| 验证 | 状态(断言结果) | 交互(断言调用) |
| 隔离 | 较低(集成) | 较高(仅单元) |
| 重构 | 更容易 | 更难(模拟中断) |
| 设计反馈 | 从使用中产生 | 从一开始就明确 |
代理协调
qe-test-generator: 生成两个学派的测试qe-test-implementer: 实现最小化代码(绿色)qe-test-refactorer: 安全重构(重构)
芝加哥学派(基于状态)
哲学: 通过公共API测试可观察行为。保持测试接近消费者使用。
// 状态验证 - 测试最终结果
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);
});
});
芝加哥学派闪耀时:
- 具有清晰状态的领域逻辑
- 算法和计算
- 值对象(
Money,Email) - 简单协作
- 学习新领域
伦敦学派(基于模拟)
哲学: 隔离测试每个单元。关注对象如何协作。
// 交互验证 - 测试方法调用
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);
});
});
伦敦学派闪耀时:
- 外部集成(数据库、API)
- 带有副作用的命令模式
- 复杂工作流
- 慢速操作(网络、I/O)
混合方法(推荐)
// 伦敦用于控制器(外部依赖)
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();
});
});
// 芝加哥用于领域逻辑
describe('OrderService', () => {
it('applies discount when threshold met', () => {
const service = new OrderService();
const order = service.create({ items: [...], total: 150 });
expect(order.discount).toBe(15); // 当总额超过$100时打10%折扣
});
});
常见陷阱
❌ 过度模拟(伦敦学派)
// 错误 - 模拟一切
const product = { getName: jest.fn(), getPrice: jest.fn() };
更好: 仅模拟外部依赖。
❌ 模拟内部
// 错误 - 测试私有方法
expect(order._calculateSubtotal).toHaveBeenCalled();
更好: 仅测试公共行为。
❌ 测试痛苦 = 设计痛苦
- 需要许多模拟? → 依赖过多
- 难以设置? → 构造函数做得太多
- 没有数据库无法测试? → 耦合问题
代理辅助的TDD
// 代理生成两个学派的测试
await Task("Generate Tests", {
style: 'chicago', // 或 'london'
target: 'src/domain/Order.ts',
focus: 'state-verification' // 或 'collaboration-patterns'
}, "qe-test-generator");
// 代理-人类乒乓式TDD
// 人类编写测试概念
const testIdea = "Order applies 10% discount when total > $100";
// 代理生成正式的失败测试(红色)
await Task("Create Failing Test", testIdea, "qe-test-generator");
// 人类编写最小化代码(绿色)
// 代理建议重构
await Task("Suggest Refactorings", { preserveTests: true }, "qe-test-refactorer");
代理协调提示
内存命名空间
aqe/tdd/
├── test-plan/* - TDD会话计划
├── red-phase/* - 生成的失败测试
├── green-phase/* - 实现代码
└── refactor-phase/* - 重构建议
舰队协调
const tddFleet = await FleetManager.coordinate({
workflow: 'red-green-refactor',
agents: {
testGenerator: 'qe-test-generator',
testExecutor: 'qe-test-executor',
qualityAnalyzer: 'qe-quality-analyzer'
},
mode: 'sequential'
});
相关技能
- agentic-quality-engineering - 带代理协调的TDD
- refactoring-patterns - 重构阶段技术
- api-testing-patterns - 伦敦学派用于API测试
记住
芝加哥: 测试状态,使用真实对象,自由重构 伦敦: 测试交互,模拟依赖,首先设计接口 两者: 首先编写测试,使其通过,重构
没有“正确”的学派。根据上下文选择。根据需要混合。目标:设计良好、测试过的代码。
使用代理: 代理擅长生成测试、验证绿色阶段和建议重构。使用代理以保持TDD纪律,同时人类专注于设计决策。