关于 tdd-london-chicago
为开发者和团队提供伦敦学派与芝加哥学派的 TDD 实践指南,帮助选择测试风格并遵循 Red、Green、Refactor 循环。内容涵盖混合使用方式及 Agent 协作提示。
主要功能
- 01按代码类型选择测试风格
- 02指导 Red、Green、Refactor 循环
- 03比较真实对象与模拟对象
- 04说明混合测试策略
- 05提供 Agent 协作提示
适用场景
- 01为新功能采用测试先行开发
- 02为遗留代码补充测试覆盖
- 03在模拟与真实对象间选择
- 04向团队讲解 TDD 实践
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ proffesor-for-testing/ agentic-qe --skill tdd-london-chicago安装后在 Claude Code 中输入/tdd-london-chicago确认已加载。
附带文件schemas/output.jsonscripts/validate-config.json
详细介绍
测试驱动开发:伦敦学派与芝加哥学派
<default_to_action> 在实施 TDD 或选择测试风格时:
- 识别代码类型:领域逻辑 → 芝加哥学派,外部依赖 → 伦敦学派
- 先编写失败的测试(Red 阶段)
- 实现最少的代码使测试通过(Green 阶段)
- 在保持测试通过的同时重构(Refactor 阶段)
- 为下一个功能重复此循环
快速选择风格:
- 纯函数/计算 → 芝加哥学派(真实对象、状态验证)
- 带依赖项的控制器/服务 → 伦敦学派(模拟对象、交互验证)
- 值对象 → 芝加哥学派(测试最终状态)
- API 集成 → 伦敦学派(模拟外部服务)
- 在实践中混合使用两者(控制器使用伦敦学派,领域逻辑使用芝加哥学派)
关键成功因素:
- 测试驱动设计,而不只是验证设计
- 先让测试失败,确保它确实在测试某些内容
- 编写最少的代码——不实现测试范围之外的功能 </default_to_action>
快速参考卡
适用场景
- 以测试优先的方式启动新功能
- 为旧代码添加测试覆盖并进行重构
- 向团队传授 TDD 实践
- 在模拟对象与真实对象之间进行选择
TDD 循环
| 阶段 | 操作 | 原则 |
|---|---|---|
| Red | 编写失败的测试 | 确认测试失败,并检查错误消息是否清晰 |
| Green | 编写最少的代码使测试通过 | 不添加额外功能,不要重构 |
| Refactor | 改进结构 | 保持测试通过,不添加新功能 |
学派对比
| 方面 | 芝加哥学派(古典派) | 伦敦学派(模拟派) |
|---|---|---|
| 协作者 | 真实对象 | 模拟对象/桩对象 |
| 验证方式 | 状态(断言结果) | 交互(断言调用) |
| 隔离程度 | 较低(集成) | 较高(仅单元测试) |
| 重构 | 更容易 | 更难(模拟对象会失效) |
| 设计反馈 | 在使用过程中显现 | 从一开始就明确 |
Agent 协作
qe-test-generator:生成两种学派的测试qe-test-implementer:实现最少的代码(Green)qe-test-refactorer:安全重构(Refactor)
芝加哥学派(基于状态)
理念: 通过公共 API 测试可观察行为。让测试贴近使用者的使用方式。
// 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);
});
});
芝加哥学派的优势场景:
- 状态明确的领域逻辑
- 算法和计算
- 值对象(
Money、Email) - 简单的协作关系
- 学习新的领域
伦敦学派(基于模拟对象)
理念: 隔离测试每个单元。关注对象之间如何协作。
// 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);
});
});
伦敦学派的优势场景:
- 外部集成(数据库、API)
- 带有副作用的命令模式
- 复杂工作流
- 耗时操作(网络、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
});
});
常见陷阱
❌ 过度使用模拟对象(伦敦学派)
// BAD - mocking everything
const product = { getName: jest.fn(), getPrice: jest.fn() };
更好的做法: 只模拟外部依赖项。
❌ 模拟内部实现
// BAD - testing private methods
expect(order._calculateSubtotal).toHaveBeenCalled();
更好的做法: 只测试公共行为。
❌ 测试痛点 = 设计痛点
- 需要很多模拟对象?→ 依赖项太多
- 难以搭建测试?→ 构造函数做的事情太多
- 无法脱离数据库进行测试?→ 耦合问题
Agent 辅助的 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 协作提示
记忆命名空间
aqe/tdd/
├── test-plan/* - TDD session plans
├── red-phase/* - Failing tests generated
├── green-phase/* - Implementation code
└── refactor-phase/* - Refactoring suggestions
集群协作
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 - 通过 Agent 协作进行 TDD
- refactoring-patterns - Refactor 阶段的技巧
- api-testing-patterns - 用于 API 测试的伦敦学派
请记住
芝加哥学派: 测试状态,使用真实对象,自由重构 伦敦学派: 测试交互,模拟依赖项,先设计接口 两者皆可: 先编写测试,让测试通过,再重构
两种方法都没有绝对的“正确”。根据上下文选择,必要时混合使用。目标是编写设计良好且经过测试的代码。
使用 Agent: Agent 擅长生成测试、验证 Green 阶段以及提出重构建议。利用 Agent 保持 TDD 纪律,让人类专注于设计决策。
注意事项
- Agent 跳过 Red 阶段,同时编写测试和实现——通过先运行测试来落实“测试必须先失败”这一要求,然后再编写代码
- 伦敦学派过度使用模拟会导致测试十分脆弱,任何重构都会使其失败——应在架构边界处进行模拟,而不是对每个函数都进行模拟
- 随着集成范围扩大,芝加哥学派的测试会变得缓慢——应严格控制测试边界
- Agent 默认对所有内容使用 jest.mock()——应优先使用依赖注入来提高可测试性
- 重构阶段最容易让 Agent 偷工减料——通过确认测试输出完全一致,验证行为没有变化
评论
支持 Markdown