agentic-qe 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/qx-partner.md +17 -4
- package/.claude/skills/accessibility-testing/SKILL.md +144 -692
- package/.claude/skills/agentic-quality-engineering/SKILL.md +176 -529
- package/.claude/skills/api-testing-patterns/SKILL.md +180 -560
- package/.claude/skills/brutal-honesty-review/SKILL.md +113 -603
- package/.claude/skills/bug-reporting-excellence/SKILL.md +116 -517
- package/.claude/skills/chaos-engineering-resilience/SKILL.md +127 -72
- package/.claude/skills/cicd-pipeline-qe-orchestrator/SKILL.md +209 -404
- package/.claude/skills/code-review-quality/SKILL.md +158 -608
- package/.claude/skills/compatibility-testing/SKILL.md +148 -38
- package/.claude/skills/compliance-testing/SKILL.md +132 -63
- package/.claude/skills/consultancy-practices/SKILL.md +114 -446
- package/.claude/skills/context-driven-testing/SKILL.md +117 -381
- package/.claude/skills/contract-testing/SKILL.md +176 -141
- package/.claude/skills/database-testing/SKILL.md +137 -130
- package/.claude/skills/exploratory-testing-advanced/SKILL.md +160 -629
- package/.claude/skills/holistic-testing-pact/SKILL.md +140 -188
- package/.claude/skills/localization-testing/SKILL.md +145 -33
- package/.claude/skills/mobile-testing/SKILL.md +132 -448
- package/.claude/skills/mutation-testing/SKILL.md +147 -41
- package/.claude/skills/performance-testing/SKILL.md +200 -546
- package/.claude/skills/quality-metrics/SKILL.md +164 -519
- package/.claude/skills/refactoring-patterns/SKILL.md +132 -699
- package/.claude/skills/regression-testing/SKILL.md +120 -926
- package/.claude/skills/risk-based-testing/SKILL.md +157 -660
- package/.claude/skills/security-testing/SKILL.md +199 -538
- package/.claude/skills/sherlock-review/SKILL.md +163 -699
- package/.claude/skills/shift-left-testing/SKILL.md +161 -465
- package/.claude/skills/shift-right-testing/SKILL.md +161 -519
- package/.claude/skills/six-thinking-hats/SKILL.md +175 -1110
- package/.claude/skills/skills-manifest.json +71 -20
- package/.claude/skills/tdd-london-chicago/SKILL.md +131 -448
- package/.claude/skills/technical-writing/SKILL.md +103 -154
- package/.claude/skills/test-automation-strategy/SKILL.md +166 -772
- package/.claude/skills/test-data-management/SKILL.md +126 -910
- package/.claude/skills/test-design-techniques/SKILL.md +179 -89
- package/.claude/skills/test-environment-management/SKILL.md +136 -91
- package/.claude/skills/test-reporting-analytics/SKILL.md +169 -92
- package/.claude/skills/testability-scoring/SKILL.md +172 -538
- package/.claude/skills/testability-scoring/scripts/generate-html-report.js +0 -0
- package/.claude/skills/visual-testing-advanced/SKILL.md +155 -78
- package/.claude/skills/xp-practices/SKILL.md +151 -587
- package/CHANGELOG.md +48 -0
- package/README.md +23 -16
- package/dist/agents/QXPartnerAgent.d.ts +8 -1
- package/dist/agents/QXPartnerAgent.d.ts.map +1 -1
- package/dist/agents/QXPartnerAgent.js +1174 -112
- package/dist/agents/QXPartnerAgent.js.map +1 -1
- package/dist/agents/lifecycle/AgentLifecycleManager.d.ts.map +1 -1
- package/dist/agents/lifecycle/AgentLifecycleManager.js +34 -31
- package/dist/agents/lifecycle/AgentLifecycleManager.js.map +1 -1
- package/dist/cli/commands/init-claude-md-template.d.ts.map +1 -1
- package/dist/cli/commands/init-claude-md-template.js +14 -0
- package/dist/cli/commands/init-claude-md-template.js.map +1 -1
- package/dist/core/SwarmCoordinator.d.ts +180 -0
- package/dist/core/SwarmCoordinator.d.ts.map +1 -0
- package/dist/core/SwarmCoordinator.js +473 -0
- package/dist/core/SwarmCoordinator.js.map +1 -0
- package/dist/core/metrics/MetricsAggregator.d.ts +228 -0
- package/dist/core/metrics/MetricsAggregator.d.ts.map +1 -0
- package/dist/core/metrics/MetricsAggregator.js +482 -0
- package/dist/core/metrics/MetricsAggregator.js.map +1 -0
- package/dist/core/metrics/index.d.ts +5 -0
- package/dist/core/metrics/index.d.ts.map +1 -0
- package/dist/core/metrics/index.js +11 -0
- package/dist/core/metrics/index.js.map +1 -0
- package/dist/core/optimization/SwarmOptimizer.d.ts +5 -0
- package/dist/core/optimization/SwarmOptimizer.d.ts.map +1 -1
- package/dist/core/optimization/SwarmOptimizer.js +17 -0
- package/dist/core/optimization/SwarmOptimizer.js.map +1 -1
- package/dist/core/orchestration/AdaptiveScheduler.d.ts +190 -0
- package/dist/core/orchestration/AdaptiveScheduler.d.ts.map +1 -0
- package/dist/core/orchestration/AdaptiveScheduler.js +460 -0
- package/dist/core/orchestration/AdaptiveScheduler.js.map +1 -0
- package/dist/core/orchestration/WorkflowOrchestrator.d.ts +13 -0
- package/dist/core/orchestration/WorkflowOrchestrator.d.ts.map +1 -1
- package/dist/core/orchestration/WorkflowOrchestrator.js +32 -0
- package/dist/core/orchestration/WorkflowOrchestrator.js.map +1 -1
- package/dist/core/recovery/CircuitBreaker.d.ts +176 -0
- package/dist/core/recovery/CircuitBreaker.d.ts.map +1 -0
- package/dist/core/recovery/CircuitBreaker.js +382 -0
- package/dist/core/recovery/CircuitBreaker.js.map +1 -0
- package/dist/core/recovery/RecoveryOrchestrator.d.ts +186 -0
- package/dist/core/recovery/RecoveryOrchestrator.d.ts.map +1 -0
- package/dist/core/recovery/RecoveryOrchestrator.js +476 -0
- package/dist/core/recovery/RecoveryOrchestrator.js.map +1 -0
- package/dist/core/recovery/RetryStrategy.d.ts +127 -0
- package/dist/core/recovery/RetryStrategy.d.ts.map +1 -0
- package/dist/core/recovery/RetryStrategy.js +314 -0
- package/dist/core/recovery/RetryStrategy.js.map +1 -0
- package/dist/core/recovery/index.d.ts +8 -0
- package/dist/core/recovery/index.d.ts.map +1 -0
- package/dist/core/recovery/index.js +27 -0
- package/dist/core/recovery/index.js.map +1 -0
- package/dist/core/skills/DependencyResolver.d.ts +99 -0
- package/dist/core/skills/DependencyResolver.d.ts.map +1 -0
- package/dist/core/skills/DependencyResolver.js +260 -0
- package/dist/core/skills/DependencyResolver.js.map +1 -0
- package/dist/core/skills/ManifestGenerator.d.ts +114 -0
- package/dist/core/skills/ManifestGenerator.d.ts.map +1 -0
- package/dist/core/skills/ManifestGenerator.js +449 -0
- package/dist/core/skills/ManifestGenerator.js.map +1 -0
- package/dist/core/skills/index.d.ts +9 -0
- package/dist/core/skills/index.d.ts.map +1 -0
- package/dist/core/skills/index.js +24 -0
- package/dist/core/skills/index.js.map +1 -0
- package/dist/mcp/server.d.ts +9 -9
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +1 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/types/qx.d.ts +39 -7
- package/dist/types/qx.d.ts.map +1 -1
- package/dist/types/qx.js.map +1 -1
- package/dist/visualization/api/RestEndpoints.js +1 -1
- package/dist/visualization/api/RestEndpoints.js.map +1 -1
- package/package.json +13 -55
|
@@ -1,550 +1,234 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: tdd-london-chicago
|
|
3
|
-
description: Apply
|
|
3
|
+
description: "Apply London (mock-based) and Chicago (state-based) TDD schools. Use when practicing test-driven development or choosing testing style for your context."
|
|
4
|
+
category: development-practices
|
|
5
|
+
priority: high
|
|
6
|
+
tokenEstimate: 1100
|
|
7
|
+
agents: [qe-test-generator, qe-test-implementer, qe-test-refactorer]
|
|
8
|
+
implementation_status: optimized
|
|
9
|
+
optimization_version: 1.0
|
|
10
|
+
last_optimized: 2025-12-02
|
|
11
|
+
dependencies: []
|
|
12
|
+
quick_reference_card: true
|
|
13
|
+
tags: [tdd, testing, london-school, chicago-school, red-green-refactor, mocks]
|
|
4
14
|
---
|
|
5
15
|
|
|
6
16
|
# Test-Driven Development: London & Chicago Schools
|
|
7
17
|
|
|
8
|
-
|
|
18
|
+
<default_to_action>
|
|
19
|
+
When implementing TDD or choosing testing style:
|
|
20
|
+
1. IDENTIFY code type: domain logic → Chicago, external deps → London
|
|
21
|
+
2. WRITE failing test first (Red phase)
|
|
22
|
+
3. IMPLEMENT minimal code to pass (Green phase)
|
|
23
|
+
4. REFACTOR while keeping tests green (Refactor phase)
|
|
24
|
+
5. REPEAT cycle for next functionality
|
|
25
|
+
|
|
26
|
+
**Quick Style Selection:**
|
|
27
|
+
- Pure functions/calculations → Chicago (real objects, state verification)
|
|
28
|
+
- Controllers/services with deps → London (mocks, interaction verification)
|
|
29
|
+
- Value objects → Chicago (test final state)
|
|
30
|
+
- API integrations → London (mock external services)
|
|
31
|
+
- Mix both in practice (London for controllers, Chicago for domain)
|
|
32
|
+
|
|
33
|
+
**Critical Success Factors:**
|
|
34
|
+
- Tests drive design, not just verify it
|
|
35
|
+
- Make tests fail first to ensure they test something
|
|
36
|
+
- Write minimal code - no features beyond what's tested
|
|
37
|
+
</default_to_action>
|
|
38
|
+
|
|
39
|
+
## Quick Reference Card
|
|
40
|
+
|
|
41
|
+
### When to Use
|
|
42
|
+
- Starting new feature with test-first approach
|
|
43
|
+
- Refactoring legacy code with test coverage
|
|
44
|
+
- Teaching TDD practices to team
|
|
45
|
+
- Choosing between mocking vs real objects
|
|
46
|
+
|
|
47
|
+
### TDD Cycle
|
|
48
|
+
| Phase | Action | Discipline |
|
|
49
|
+
|-------|--------|------------|
|
|
50
|
+
| **Red** | Write failing test | Verify it fails, check message is clear |
|
|
51
|
+
| **Green** | Minimal code to pass | No extra features, don't refactor |
|
|
52
|
+
| **Refactor** | Improve structure | Keep tests passing, no new functionality |
|
|
53
|
+
|
|
54
|
+
### School Comparison
|
|
55
|
+
| Aspect | Chicago (Classicist) | London (Mockist) |
|
|
56
|
+
|--------|---------------------|------------------|
|
|
57
|
+
| Collaborators | Real objects | Mocks/stubs |
|
|
58
|
+
| Verification | State (assert outcomes) | Interaction (assert calls) |
|
|
59
|
+
| Isolation | Lower (integrated) | Higher (unit only) |
|
|
60
|
+
| Refactoring | Easier | Harder (mocks break) |
|
|
61
|
+
| Design feedback | Emerges from use | Explicit from start |
|
|
62
|
+
|
|
63
|
+
### Agent Coordination
|
|
64
|
+
- `qe-test-generator`: Generate tests in both schools
|
|
65
|
+
- `qe-test-implementer`: Implement minimal code (Green)
|
|
66
|
+
- `qe-test-refactorer`: Safe refactoring (Refactor)
|
|
9
67
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
1. **Red:** Write a failing test for the next bit of functionality
|
|
13
|
-
2. **Green:** Write just enough code to make the test pass
|
|
14
|
-
3. **Refactor:** Improve the code without changing behavior
|
|
15
|
-
|
|
16
|
-
**Key principle:** Tests drive design, not just verify it.
|
|
17
|
-
|
|
18
|
-
## Chicago School (Detroit School / Classicist)
|
|
19
|
-
|
|
20
|
-
### Philosophy
|
|
21
|
-
Test observable behavior through the public API. Focus on state verification. Keep tests close to how users/consumers will interact with the code.
|
|
68
|
+
---
|
|
22
69
|
|
|
23
|
-
|
|
24
|
-
- Write tests against real objects
|
|
25
|
-
- Minimize use of mocks/stubs
|
|
26
|
-
- Tests typically involve multiple units working together
|
|
27
|
-
- Inside-out or outside-in (both work)
|
|
70
|
+
## Chicago School (State-Based)
|
|
28
71
|
|
|
29
|
-
|
|
72
|
+
**Philosophy:** Test observable behavior through public API. Keep tests close to consumer usage.
|
|
30
73
|
|
|
31
74
|
```javascript
|
|
32
|
-
//
|
|
75
|
+
// State verification - test final outcome
|
|
33
76
|
describe('Order', () => {
|
|
34
77
|
it('calculates total with tax', () => {
|
|
35
78
|
const order = new Order();
|
|
36
79
|
order.addItem(new Product('Widget', 10.00), 2);
|
|
37
80
|
order.addItem(new Product('Gadget', 15.00), 1);
|
|
38
|
-
|
|
39
|
-
expect(order.totalWithTax(0.10)).toBe(38.50);
|
|
81
|
+
|
|
82
|
+
expect(order.totalWithTax(0.10)).toBe(38.50);
|
|
40
83
|
});
|
|
41
84
|
});
|
|
42
|
-
|
|
43
|
-
// Implementation
|
|
44
|
-
class Order {
|
|
45
|
-
constructor() {
|
|
46
|
-
this.items = [];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
addItem(product, quantity) {
|
|
50
|
-
this.items.push({ product, quantity });
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
totalWithTax(taxRate) {
|
|
54
|
-
const subtotal = this.items.reduce((sum, item) =>
|
|
55
|
-
sum + (item.product.price * item.quantity), 0
|
|
56
|
-
);
|
|
57
|
-
return subtotal * (1 + taxRate);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
class Product {
|
|
62
|
-
constructor(name, price) {
|
|
63
|
-
this.name = name;
|
|
64
|
-
this.price = price;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
85
|
```
|
|
68
86
|
|
|
69
|
-
|
|
70
|
-
- **Real collaborators:** Order uses actual Product objects
|
|
71
|
-
- **State verification:** Assert on the final total
|
|
72
|
-
- **Integrated test:** Multiple objects work together
|
|
73
|
-
- **Refactoring safety:** Can change internal implementation freely
|
|
74
|
-
|
|
75
|
-
### When Chicago Shines
|
|
87
|
+
**When Chicago Shines:**
|
|
76
88
|
- Domain logic with clear state
|
|
77
89
|
- Algorithms and calculations
|
|
78
|
-
-
|
|
79
|
-
-
|
|
80
|
-
- Learning
|
|
81
|
-
|
|
82
|
-
## London School (Mockist)
|
|
90
|
+
- Value objects (`Money`, `Email`)
|
|
91
|
+
- Simple collaborations
|
|
92
|
+
- Learning new domain
|
|
83
93
|
|
|
84
|
-
|
|
85
|
-
Test each unit in isolation. Focus on interaction verification. Design emerges through defining interfaces and collaborations first.
|
|
94
|
+
---
|
|
86
95
|
|
|
87
|
-
|
|
88
|
-
- Mock external dependencies
|
|
89
|
-
- Outside-in development (start from entry point)
|
|
90
|
-
- Tests focus on how objects collaborate
|
|
91
|
-
- Discover interfaces through testing
|
|
96
|
+
## London School (Mock-Based)
|
|
92
97
|
|
|
93
|
-
|
|
98
|
+
**Philosophy:** Test each unit in isolation. Focus on how objects collaborate.
|
|
94
99
|
|
|
95
100
|
```javascript
|
|
96
|
-
//
|
|
101
|
+
// Interaction verification - test method calls
|
|
97
102
|
describe('Order', () => {
|
|
98
|
-
it('
|
|
103
|
+
it('delegates tax calculation', () => {
|
|
99
104
|
const taxCalculator = {
|
|
100
105
|
calculateTax: jest.fn().mockReturnValue(3.50)
|
|
101
106
|
};
|
|
102
|
-
|
|
103
107
|
const order = new Order(taxCalculator);
|
|
104
108
|
order.addItem({ price: 10 }, 2);
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
expect(taxCalculator.calculateTax).toHaveBeenCalledWith(35.00);
|
|
110
|
-
expect(total).toBe(38.50);
|
|
109
|
+
|
|
110
|
+
order.totalWithTax();
|
|
111
|
+
|
|
112
|
+
expect(taxCalculator.calculateTax).toHaveBeenCalledWith(20.00);
|
|
111
113
|
});
|
|
112
114
|
});
|
|
113
|
-
|
|
114
|
-
// Implementation
|
|
115
|
-
class Order {
|
|
116
|
-
constructor(taxCalculator) {
|
|
117
|
-
this.taxCalculator = taxCalculator;
|
|
118
|
-
this.items = [];
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
addItem(product, quantity) {
|
|
122
|
-
this.items.push({ product, quantity });
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
totalWithTax() {
|
|
126
|
-
const subtotal = this.items.reduce((sum, item) =>
|
|
127
|
-
sum + (item.product.price * item.quantity), 0
|
|
128
|
-
);
|
|
129
|
-
const tax = this.taxCalculator.calculateTax(subtotal);
|
|
130
|
-
return subtotal + tax;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
115
|
```
|
|
134
116
|
|
|
135
|
-
|
|
136
|
-
-
|
|
137
|
-
-
|
|
138
|
-
-
|
|
139
|
-
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
- When testing would be slow without mocks
|
|
145
|
-
- Designing new systems (interfaces emerge naturally)
|
|
146
|
-
- Code with heavy I/O or side effects
|
|
147
|
-
|
|
148
|
-
## Key Differences
|
|
149
|
-
|
|
150
|
-
| Aspect | Chicago | London |
|
|
151
|
-
|--------|---------|--------|
|
|
152
|
-
| **Collaborators** | Real objects | Mocks/stubs |
|
|
153
|
-
| **Verification** | State (assert outcomes) | Interaction (assert method calls) |
|
|
154
|
-
| **Isolation** | Lower (integrated units) | Higher (unit in isolation) |
|
|
155
|
-
| **Refactoring** | Easier (fewer test changes) | Harder (mocks may break) |
|
|
156
|
-
| **Design feedback** | Emerge from use | Explicit from start |
|
|
157
|
-
| **Test speed** | Can be slower | Usually faster |
|
|
158
|
-
|
|
159
|
-
## Practical Guidance: Which to Use?
|
|
160
|
-
|
|
161
|
-
### Use Chicago When:
|
|
162
|
-
- **Pure functions and calculations**
|
|
163
|
-
- `calculateDiscount(price, percentage)`
|
|
164
|
-
- `formatCurrency(amount)`
|
|
165
|
-
|
|
166
|
-
- **Value objects**
|
|
167
|
-
- `Money`, `Email`, `PhoneNumber`
|
|
168
|
-
|
|
169
|
-
- **Simple collaborations**
|
|
170
|
-
- Few dependencies, straightforward interactions
|
|
171
|
-
|
|
172
|
-
- **Learning phase**
|
|
173
|
-
- Understanding domain, exploring design
|
|
174
|
-
|
|
175
|
-
### Use London When:
|
|
176
|
-
- **External integrations**
|
|
177
|
-
- Database access, API calls, file I/O
|
|
178
|
-
|
|
179
|
-
- **Command patterns**
|
|
180
|
-
- Actions that change state elsewhere
|
|
181
|
-
|
|
182
|
-
- **Complex workflows**
|
|
183
|
-
- Multiple objects coordinating
|
|
184
|
-
|
|
185
|
-
- **Slow operations**
|
|
186
|
-
- Network calls, heavy computations
|
|
187
|
-
|
|
188
|
-
### Mix Both (Common in Practice)
|
|
117
|
+
**When London Shines:**
|
|
118
|
+
- External integrations (DB, APIs)
|
|
119
|
+
- Command patterns with side effects
|
|
120
|
+
- Complex workflows
|
|
121
|
+
- Slow operations (network, I/O)
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Mixed Approach (Recommended)
|
|
189
126
|
|
|
190
127
|
```javascript
|
|
191
|
-
// London
|
|
128
|
+
// London for controller (external deps)
|
|
192
129
|
describe('OrderController', () => {
|
|
193
130
|
it('creates order and sends confirmation', async () => {
|
|
194
131
|
const orderService = { create: jest.fn().mockResolvedValue({ id: 123 }) };
|
|
195
132
|
const emailService = { send: jest.fn() };
|
|
196
|
-
|
|
133
|
+
|
|
197
134
|
const controller = new OrderController(orderService, emailService);
|
|
198
135
|
await controller.placeOrder(orderData);
|
|
199
|
-
|
|
136
|
+
|
|
200
137
|
expect(orderService.create).toHaveBeenCalledWith(orderData);
|
|
201
138
|
expect(emailService.send).toHaveBeenCalled();
|
|
202
139
|
});
|
|
203
140
|
});
|
|
204
141
|
|
|
205
|
-
// Chicago
|
|
142
|
+
// Chicago for domain logic
|
|
206
143
|
describe('OrderService', () => {
|
|
207
144
|
it('applies discount when threshold met', () => {
|
|
208
145
|
const service = new OrderService();
|
|
209
146
|
const order = service.create({ items: [...], total: 150 });
|
|
210
|
-
|
|
211
|
-
expect(order.discount).toBe(15); // 10% off
|
|
147
|
+
|
|
148
|
+
expect(order.discount).toBe(15); // 10% off > $100
|
|
212
149
|
});
|
|
213
150
|
});
|
|
214
151
|
```
|
|
215
152
|
|
|
216
|
-
|
|
153
|
+
---
|
|
217
154
|
|
|
218
|
-
|
|
219
|
-
**Problem:** Mocking everything makes tests brittle.
|
|
155
|
+
## Common Pitfalls
|
|
220
156
|
|
|
157
|
+
### ❌ Over-Mocking (London)
|
|
221
158
|
```javascript
|
|
222
|
-
//
|
|
159
|
+
// BAD - mocking everything
|
|
223
160
|
const product = { getName: jest.fn(), getPrice: jest.fn() };
|
|
224
161
|
```
|
|
162
|
+
**Better:** Only mock external dependencies.
|
|
225
163
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
### Under-Testing (Chicago)
|
|
229
|
-
**Problem:** Integration tests miss edge cases in individual units.
|
|
230
|
-
|
|
231
|
-
**Solution:** Add unit tests for complex logic, keep integration tests for happy paths.
|
|
232
|
-
|
|
233
|
-
### Mocking Implementation Details (London)
|
|
234
|
-
**Problem:** Tests break when refactoring internals.
|
|
235
|
-
|
|
164
|
+
### ❌ Mocking Internals
|
|
236
165
|
```javascript
|
|
237
|
-
// BAD - testing private
|
|
166
|
+
// BAD - testing private methods
|
|
238
167
|
expect(order._calculateSubtotal).toHaveBeenCalled();
|
|
239
168
|
```
|
|
169
|
+
**Better:** Test public behavior only.
|
|
240
170
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
### Ignoring Test Pain (Both)
|
|
244
|
-
**Problem:** Hard-to-test code = poorly designed code.
|
|
245
|
-
|
|
246
|
-
**Listen to tests:**
|
|
171
|
+
### ❌ Test Pain = Design Pain
|
|
247
172
|
- Need many mocks? → Too many dependencies
|
|
248
173
|
- Hard to set up? → Constructor does too much
|
|
249
|
-
-
|
|
250
|
-
- Can't test without real database? → Coupling to infrastructure
|
|
251
|
-
|
|
252
|
-
## TDD Rhythm
|
|
253
|
-
|
|
254
|
-
### Micro-Level (Minutes)
|
|
255
|
-
1. Write tiny failing test
|
|
256
|
-
2. Write minimal code to pass
|
|
257
|
-
3. Quick refactor
|
|
258
|
-
4. Repeat
|
|
259
|
-
|
|
260
|
-
### Macro-Level (Hours)
|
|
261
|
-
1. Sketch out component responsibilities
|
|
262
|
-
2. TDD the easiest piece first
|
|
263
|
-
3. TDD the next piece
|
|
264
|
-
4. Refactor across components
|
|
265
|
-
5. Continue building out
|
|
266
|
-
|
|
267
|
-
### Red-Green-Refactor Discipline
|
|
268
|
-
|
|
269
|
-
**Red phase:**
|
|
270
|
-
- Run test, verify it fails
|
|
271
|
-
- Check failure message is clear
|
|
272
|
-
- Don't write production code yet
|
|
273
|
-
|
|
274
|
-
**Green phase:**
|
|
275
|
-
- Write simplest code to pass
|
|
276
|
-
- Don't add features not tested yet
|
|
277
|
-
- Don't refactor yet
|
|
278
|
-
- Verify test passes
|
|
279
|
-
|
|
280
|
-
**Refactor phase:**
|
|
281
|
-
- Improve code structure
|
|
282
|
-
- Keep tests passing
|
|
283
|
-
- Stop when code is clean enough
|
|
284
|
-
- Don't add new functionality
|
|
285
|
-
|
|
286
|
-
## Examples of Good TDD Flow
|
|
287
|
-
|
|
288
|
-
### Chicago Example: Shopping Cart
|
|
289
|
-
|
|
290
|
-
```javascript
|
|
291
|
-
// Test 1: Empty cart
|
|
292
|
-
test('new cart has zero items', () => {
|
|
293
|
-
const cart = new Cart();
|
|
294
|
-
expect(cart.itemCount()).toBe(0);
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
// Make it pass
|
|
298
|
-
class Cart {
|
|
299
|
-
itemCount() { return 0; }
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// Test 2: Add item
|
|
303
|
-
test('adding item increases count', () => {
|
|
304
|
-
const cart = new Cart();
|
|
305
|
-
cart.add({ id: 1, name: 'Widget' });
|
|
306
|
-
expect(cart.itemCount()).toBe(1);
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
// Make it pass
|
|
310
|
-
class Cart {
|
|
311
|
-
constructor() { this.items = []; }
|
|
312
|
-
add(item) { this.items.push(item); }
|
|
313
|
-
itemCount() { return this.items.length; }
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// Refactor: Extract to method
|
|
317
|
-
class Cart {
|
|
318
|
-
constructor() { this.items = []; }
|
|
319
|
-
add(item) { this.items.push(item); }
|
|
320
|
-
itemCount() { return this.items.length; }
|
|
321
|
-
}
|
|
322
|
-
// (No refactor needed yet - code is simple)
|
|
323
|
-
|
|
324
|
-
// Continue with more tests...
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
### London Example: Payment Processor
|
|
328
|
-
|
|
329
|
-
```javascript
|
|
330
|
-
// Test: Successful payment
|
|
331
|
-
test('charges card and records transaction', async () => {
|
|
332
|
-
const gateway = { charge: jest.fn().mockResolvedValue({ success: true }) };
|
|
333
|
-
const ledger = { record: jest.fn() };
|
|
334
|
-
|
|
335
|
-
const processor = new PaymentProcessor(gateway, ledger);
|
|
336
|
-
const result = await processor.process({ amount: 100, card: '1234' });
|
|
337
|
-
|
|
338
|
-
expect(gateway.charge).toHaveBeenCalledWith(100, '1234');
|
|
339
|
-
expect(ledger.record).toHaveBeenCalled();
|
|
340
|
-
expect(result.success).toBe(true);
|
|
341
|
-
});
|
|
174
|
+
- Can't test without database? → Coupling issue
|
|
342
175
|
|
|
343
|
-
|
|
344
|
-
class PaymentProcessor {
|
|
345
|
-
constructor(gateway, ledger) {
|
|
346
|
-
this.gateway = gateway;
|
|
347
|
-
this.ledger = ledger;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
async process(payment) {
|
|
351
|
-
const result = await this.gateway.charge(payment.amount, payment.card);
|
|
352
|
-
if (result.success) {
|
|
353
|
-
this.ledger.record({ amount: payment.amount, timestamp: Date.now() });
|
|
354
|
-
}
|
|
355
|
-
return result;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
## Benefits of TDD (Both Schools)
|
|
361
|
-
|
|
362
|
-
1. **Design feedback:** Tests show design problems early
|
|
363
|
-
2. **Living documentation:** Tests explain how code should work
|
|
364
|
-
3. **Regression safety:** Changes don't break existing behavior
|
|
365
|
-
4. **Confidence:** Refactor without fear
|
|
366
|
-
5. **Scope control:** Build only what's tested
|
|
367
|
-
6. **Debugging speed:** Failing test pinpoints issue
|
|
368
|
-
|
|
369
|
-
## When NOT to Use TDD
|
|
370
|
-
|
|
371
|
-
- **Spike/prototype code:** You're exploring, not building yet
|
|
372
|
-
- **Trivial code:** Getters/setters with no logic
|
|
373
|
-
- **UI layout:** Visual design isn't well suited to TDD
|
|
374
|
-
- **Performance optimization:** Measure first, optimize second
|
|
375
|
-
- **Learning new tech:** Get something working first, then test
|
|
376
|
-
|
|
377
|
-
## Misconceptions
|
|
378
|
-
|
|
379
|
-
**"TDD means 100% code coverage"**
|
|
380
|
-
No. TDD means tests drive development. Some code naturally emerges without direct tests (e.g., simple DTOs).
|
|
381
|
-
|
|
382
|
-
**"TDD is slower"**
|
|
383
|
-
Slower at first, faster overall. You debug less and refactor safely.
|
|
384
|
-
|
|
385
|
-
**"Tests guarantee correctness"**
|
|
386
|
-
No. Tests only verify what you thought to test. You can still miss requirements or have logical errors.
|
|
387
|
-
|
|
388
|
-
**"Must test private methods"**
|
|
389
|
-
No. Test through public API. If private method is complex enough to need tests, maybe it's actually a separate class.
|
|
390
|
-
|
|
391
|
-
## Combining with Other Practices
|
|
392
|
-
|
|
393
|
-
**TDD + Pair Programming:**
|
|
394
|
-
- Navigator writes test
|
|
395
|
-
- Driver makes it pass
|
|
396
|
-
- Switch roles frequently
|
|
397
|
-
|
|
398
|
-
**TDD + Continuous Integration:**
|
|
399
|
-
- Every commit has tests
|
|
400
|
-
- CI runs full suite
|
|
401
|
-
- Green build = deployable
|
|
402
|
-
|
|
403
|
-
**TDD + Refactoring:**
|
|
404
|
-
- Tests enable fearless refactoring
|
|
405
|
-
- Refactoring keeps tests maintainable
|
|
406
|
-
- Symbiotic relationship
|
|
407
|
-
|
|
408
|
-
## Resources
|
|
409
|
-
|
|
410
|
-
### Chicago School
|
|
411
|
-
- **Test-Driven Development by Example** by Kent Beck
|
|
412
|
-
- **Growing Object-Oriented Software Guided by Tests** by Freeman & Pryce (hybrid)
|
|
413
|
-
|
|
414
|
-
### London School
|
|
415
|
-
- **GOOS** by Freeman & Pryce (literally wrote the book)
|
|
416
|
-
- Martin Fowler's articles on mocks vs. stubs
|
|
417
|
-
|
|
418
|
-
### General
|
|
419
|
-
- **Working Effectively with Legacy Code** by Michael Feathers
|
|
420
|
-
- Uncle Bob's TDD screencasts
|
|
421
|
-
|
|
422
|
-
## Using with QE Agents
|
|
176
|
+
---
|
|
423
177
|
|
|
424
|
-
|
|
178
|
+
## Agent-Assisted TDD
|
|
425
179
|
|
|
426
|
-
**qe-test-generator** applies both schools:
|
|
427
180
|
```typescript
|
|
428
|
-
//
|
|
429
|
-
await
|
|
430
|
-
style: 'chicago',
|
|
181
|
+
// Agent generates tests in both schools
|
|
182
|
+
await Task("Generate Tests", {
|
|
183
|
+
style: 'chicago', // or 'london'
|
|
431
184
|
target: 'src/domain/Order.ts',
|
|
432
|
-
focus: 'state-verification'
|
|
433
|
-
});
|
|
434
|
-
// → Creates tests that verify final state
|
|
435
|
-
|
|
436
|
-
// London style: Generate interaction-based tests
|
|
437
|
-
await agent.generateTests({
|
|
438
|
-
style: 'london',
|
|
439
|
-
target: 'src/controllers/OrderController.ts',
|
|
440
|
-
focus: 'collaboration-patterns'
|
|
441
|
-
});
|
|
442
|
-
// → Creates tests with mocked dependencies
|
|
443
|
-
```
|
|
185
|
+
focus: 'state-verification' // or 'collaboration-patterns'
|
|
186
|
+
}, "qe-test-generator");
|
|
444
187
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
```typescript
|
|
448
|
-
// Red: Human writes failing test concept
|
|
188
|
+
// Agent-human ping-pong TDD
|
|
189
|
+
// Human writes test concept
|
|
449
190
|
const testIdea = "Order applies 10% discount when total > $100";
|
|
450
191
|
|
|
451
|
-
// Agent generates formal test (Red)
|
|
452
|
-
|
|
453
|
-
// → Generates complete test that fails
|
|
192
|
+
// Agent generates formal failing test (Red)
|
|
193
|
+
await Task("Create Failing Test", testIdea, "qe-test-generator");
|
|
454
194
|
|
|
455
195
|
// Human writes minimal code (Green)
|
|
456
|
-
// ... implementation code ...
|
|
457
|
-
|
|
458
|
-
// Agent validates green phase
|
|
459
|
-
await qe-test-executor.verifyGreen(failingTest);
|
|
460
|
-
// → Confirms test passes
|
|
461
196
|
|
|
462
197
|
// Agent suggests refactorings
|
|
463
|
-
|
|
464
|
-
scope: 'src/domain/Order.ts',
|
|
465
|
-
preserveTests: true
|
|
466
|
-
});
|
|
467
|
-
// → Provides safe refactoring options
|
|
198
|
+
await Task("Suggest Refactorings", { preserveTests: true }, "qe-test-refactorer");
|
|
468
199
|
```
|
|
469
200
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
**Ping-Pong TDD with Agent:**
|
|
473
|
-
```typescript
|
|
474
|
-
// Human writes test
|
|
475
|
-
const humanTest = `
|
|
476
|
-
test('cart applies bulk discount', () => {
|
|
477
|
-
const cart = new Cart();
|
|
478
|
-
cart.addItems(10);
|
|
479
|
-
expect(cart.discount()).toBe(15);
|
|
480
|
-
});
|
|
481
|
-
`;
|
|
482
|
-
|
|
483
|
-
// Agent makes it pass
|
|
484
|
-
await qe-test-generator.implementTestLogic(humanTest);
|
|
485
|
-
// → Generates minimal implementation
|
|
201
|
+
---
|
|
486
202
|
|
|
487
|
-
|
|
488
|
-
const agentTest = await qe-test-generator.nextTest({
|
|
489
|
-
context: 'bulk-discount-edge-cases',
|
|
490
|
-
style: 'chicago'
|
|
491
|
-
});
|
|
203
|
+
## Agent Coordination Hints
|
|
492
204
|
|
|
493
|
-
|
|
494
|
-
|
|
205
|
+
### Memory Namespace
|
|
206
|
+
```
|
|
207
|
+
aqe/tdd/
|
|
208
|
+
├── test-plan/* - TDD session plans
|
|
209
|
+
├── red-phase/* - Failing tests generated
|
|
210
|
+
├── green-phase/* - Implementation code
|
|
211
|
+
└── refactor-phase/* - Refactoring suggestions
|
|
495
212
|
```
|
|
496
213
|
|
|
497
|
-
### Fleet Coordination
|
|
498
|
-
|
|
214
|
+
### Fleet Coordination
|
|
499
215
|
```typescript
|
|
500
|
-
// Multiple agents support TDD workflow
|
|
501
216
|
const tddFleet = await FleetManager.coordinate({
|
|
502
217
|
workflow: 'red-green-refactor',
|
|
503
218
|
agents: {
|
|
504
|
-
testGenerator: 'qe-test-generator',
|
|
505
|
-
testExecutor: 'qe-test-executor',
|
|
506
|
-
qualityAnalyzer: 'qe-quality-analyzer'
|
|
219
|
+
testGenerator: 'qe-test-generator',
|
|
220
|
+
testExecutor: 'qe-test-executor',
|
|
221
|
+
qualityAnalyzer: 'qe-quality-analyzer'
|
|
507
222
|
},
|
|
508
223
|
mode: 'sequential'
|
|
509
224
|
});
|
|
510
|
-
|
|
511
|
-
// Agents coordinate through TDD cycle
|
|
512
|
-
await tddFleet.executeCycle({
|
|
513
|
-
feature: 'payment-processing',
|
|
514
|
-
school: 'mixed' // Use both Chicago and London where appropriate
|
|
515
|
-
});
|
|
516
|
-
```
|
|
517
|
-
|
|
518
|
-
### Choosing TDD School with Agent Guidance
|
|
519
|
-
|
|
520
|
-
```typescript
|
|
521
|
-
// Agent analyzes code and recommends TDD approach
|
|
522
|
-
const recommendation = await qe-quality-analyzer.recommendTDDStyle({
|
|
523
|
-
codeType: 'controller',
|
|
524
|
-
dependencies: ['database', 'emailService', 'paymentGateway'],
|
|
525
|
-
complexity: 'high'
|
|
526
|
-
});
|
|
527
|
-
|
|
528
|
-
// → Recommends London school (many external dependencies)
|
|
529
|
-
// → Suggests mock patterns for database and services
|
|
530
|
-
// → Provides example test structure
|
|
531
225
|
```
|
|
532
226
|
|
|
533
227
|
---
|
|
534
228
|
|
|
535
229
|
## Related Skills
|
|
536
|
-
|
|
537
|
-
**Core Quality Practices:**
|
|
538
230
|
- [agentic-quality-engineering](../agentic-quality-engineering/) - TDD with agent coordination
|
|
539
|
-
- [context-driven-testing](../context-driven-testing/) - Choose TDD style based on context
|
|
540
|
-
|
|
541
|
-
**Development Practices:**
|
|
542
|
-
- [xp-practices](../xp-practices/) - TDD within XP workflow, ping-pong pairing
|
|
543
231
|
- [refactoring-patterns](../refactoring-patterns/) - Refactor phase techniques
|
|
544
|
-
- [code-review-quality](../code-review-quality/) - Review test quality
|
|
545
|
-
|
|
546
|
-
**Testing Approaches:**
|
|
547
|
-
- [test-automation-strategy](../test-automation-strategy/) - Where TDD fits in automation pyramid
|
|
548
232
|
- [api-testing-patterns](../api-testing-patterns/) - London school for API testing
|
|
549
233
|
|
|
550
234
|
---
|
|
@@ -553,9 +237,8 @@ const recommendation = await qe-quality-analyzer.recommendTDDStyle({
|
|
|
553
237
|
|
|
554
238
|
**Chicago:** Test state, use real objects, refactor freely
|
|
555
239
|
**London:** Test interactions, mock dependencies, design interfaces first
|
|
556
|
-
|
|
557
240
|
**Both:** Write the test first, make it pass, refactor
|
|
558
241
|
|
|
559
|
-
Neither is "right." Choose based on context. Mix as needed.
|
|
242
|
+
Neither is "right." Choose based on context. Mix as needed. Goal: well-designed, tested code.
|
|
560
243
|
|
|
561
|
-
**With Agents
|
|
244
|
+
**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.
|