sdd-full 4.2.0 → 4.3.1

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.
Files changed (127) hide show
  1. package/bin.js +98 -80
  2. package/package.json +1 -1
  3. package/skills/README.md +97 -0
  4. package/skills/call-adaptation/SKILL.md +23 -0
  5. package/skills/call-adaptation/call-adaptation-guide.md +136 -0
  6. package/skills/call-adaptation/claude-code-call-spec.md +50 -0
  7. package/skills/call-adaptation/trae-call-spec.md +56 -0
  8. package/skills/checklist.md +154 -0
  9. package/skills/design-planning/ai-coding-rules/SKILL.md +52 -0
  10. package/skills/design-planning/design-to-code/SKILL.md +53 -0
  11. package/skills/design-planning/enterprise-spec/SKILL.md +52 -3
  12. package/skills/design-planning/flutter-av/SKILL.md +44 -34
  13. package/skills/design-planning/flutter-map/SKILL.md +41 -31
  14. package/skills/design-planning/function-sdd/SKILL.md +54 -0
  15. package/skills/design-planning/sdd-code/SKILL.md +347 -0
  16. package/skills/design-planning/sdd-deploy/SKILL.md +501 -0
  17. package/skills/design-planning/sdd-ops/SKILL.md +306 -0
  18. package/skills/design-planning/sdd-test/SKILL.md +383 -0
  19. package/skills/design-planning/ui-sdd/SKILL.md +291 -0
  20. package/skills/design-planning/ui-sdd-specialized/SKILL.md +46 -40
  21. package/skills/design-planning/writing-plans/SKILL.md +144 -0
  22. package/skills/development-execution/flutter-errors/SKILL.md +44 -34
  23. package/skills/development-execution/sdd-add/SKILL.md +540 -0
  24. package/skills/development-execution/systematic-debugging/SKILL.md +298 -0
  25. package/skills/development-execution/test-driven-development/SKILL.md +373 -0
  26. package/skills/development-execution/verification-before-completion/SKILL.md +141 -0
  27. package/skills/knowledge-precipitation/claudeception/SKILL.md +96 -0
  28. package/skills/knowledge-precipitation/mempalace-auto-saver/SKILL.md +302 -0
  29. package/skills/quality-assurance/bdd-acceptance/SKILL.md +44 -37
  30. package/skills/quality-assurance/flutter-test/SKILL.md +56 -0
  31. package/skills/quality-assurance/quality-gate/SKILL.md +350 -0
  32. package/skills/quality-assurance/security-audit/SKILL.md +386 -0
  33. package/skills/release-ops/finishing-a-development-branch/SKILL.md +202 -0
  34. package/skills/release-ops/release-flow/SKILL.md +404 -0
  35. package/skills/requirement-analysis/brainstorming/SKILL.md +166 -0
  36. package/skills/requirement-analysis/competitive-brief/SKILL.md +121 -0
  37. package/skills/requirement-analysis/market-research/SKILL.md +143 -0
  38. package/skills/requirement-analysis/prd-write/SKILL.md +111 -0
  39. package/skills/requirement-analysis/requirement-completion-officer/SKILL.md +124 -0
  40. package/skills/requirement-analysis/sdd/SKILL.md +1044 -0
  41. package/skills/requirement-analysis/sdd-full/SKILL.md +717 -36
  42. package/skills/requirement-analysis/unified-flow/SKILL.md +128 -26
  43. package/skills/rules/project_rules.md +167 -0
  44. package/skills/rules/user_rules.md +254 -69
  45. package/skills/special-tools/env-check/SKILL.md +40 -34
  46. package/skills/special-tools/receiving-code-review/SKILL.md +215 -0
  47. package/skills/special-tools/requesting-code-review/SKILL.md +107 -0
  48. package/skills/special-tools/using-superpowers/SKILL.md +117 -0
  49. package/skills/templates/API-SDD.md +31 -0
  50. package/skills/templates/Andrej Karpathy AI/347/274/226/347/240/201/350/247/204/345/210/231/350/220/275/345/234/260SDD.md" +117 -0
  51. package/skills/templates/BDD/351/243/216/346/240/274/351/252/214/346/224/266/346/240/207/345/207/206SDD.md +147 -0
  52. package/skills/templates/Base-SDD.md +38 -0
  53. package/skills/templates/Brain-SDD.md +36 -0
  54. package/skills/templates/Code-SDD.md +41 -0
  55. package/skills/templates/Competitor-SDD.md +34 -0
  56. package/skills/templates/Env-SDD.md +37 -0
  57. package/skills/templates/Flutter/345/205/250/347/261/273/345/236/213/346/265/213/350/257/225/347/255/226/347/225/245SDD.md +162 -0
  58. package/skills/templates/Flutter/345/234/260/345/233/276/345/257/274/350/210/252/344/270/232/345/212/241SDD.md +136 -0
  59. package/skills/templates/Flutter/345/270/270/350/247/201/345/274/202/345/270/270/344/270/223/351/241/271SDD.md +159 -0
  60. package/skills/templates/Flutter/351/237/263/350/247/206/351/242/221/345/205/250/346/240/210SDD.md +121 -0
  61. package/skills/templates/PRD-SDD.md +45 -0
  62. package/skills/templates/SKILL.md +91 -0
  63. package/skills/templates/Test-SDD.md +34 -0
  64. package/skills/templates/UI-SDD.md +38 -0
  65. package/skills/templates/UI-SDD/344/270/223/347/224/250/346/250/241/346/235/277.md +141 -0
  66. package/skills/templates/UI/350/265/204/346/272/220/346/217/220/347/244/272/350/257/215/347/224/237/346/210/220SDD.md +67 -0
  67. package/skills/templates//344/274/201/344/270/232/347/272/247/345/205/250/346/240/210/345/267/245/347/250/213/350/247/204/350/214/203SDD.md +152 -0
  68. package/skills/templates//345/205/250/346/265/201/347/250/213SDD/350/236/215/345/220/210/344/275/223/347/263/273.md +198 -0
  69. package/skills/templates//345/212/237/350/203/275SDD/344/270/223/347/224/250/346/250/241/346/235/277.md +132 -0
  70. package/skills/templates//347/216/257/345/242/203/351/242/204/346/243/200/346/240/207/345/207/206/345/214/226SDD.md +153 -0
  71. package/skills/templates//351/253/230/344/277/235/347/234/237/350/256/276/350/256/241/350/275/254/344/273/243/347/240/201SDD.md +119 -0
  72. package/skills//345/256/214/346/225/264/345/274/200/345/217/221/346/265/201/347/250/213/346/211/213/345/206/214.md +408 -0
  73. package/skills//346/212/200/350/203/275/344/275/223/347/263/273/345/256/214/345/226/204/345/273/272/350/256/256.md +305 -0
  74. package/skills//346/212/200/350/203/275/344/275/277/347/224/250/346/214/207/345/215/227.md +285 -0
  75. package/skills//346/212/200/350/203/275/345/206/263/347/255/226/346/240/221.md +320 -0
  76. package/skills/brainstorming/SKILL.md +0 -164
  77. package/skills/brainstorming/scripts/frame-template.html +0 -214
  78. package/skills/brainstorming/scripts/helper.js +0 -88
  79. package/skills/brainstorming/scripts/server.cjs +0 -338
  80. package/skills/brainstorming/scripts/start-server.sh +0 -153
  81. package/skills/brainstorming/scripts/stop-server.sh +0 -55
  82. package/skills/brainstorming/spec-document-reviewer-prompt.md +0 -48
  83. package/skills/brainstorming/visual-companion.md +0 -286
  84. package/skills/chinese-code-review/SKILL.md +0 -277
  85. package/skills/chinese-commit-conventions/SKILL.md +0 -364
  86. package/skills/chinese-documentation/SKILL.md +0 -448
  87. package/skills/chinese-git-workflow/SKILL.md +0 -510
  88. package/skills/dispatching-parallel-agents/SKILL.md +0 -182
  89. package/skills/executing-plans/SKILL.md +0 -175
  90. package/skills/finishing-a-development-branch/SKILL.md +0 -200
  91. package/skills/mcp-builder/SKILL.md +0 -255
  92. package/skills/receiving-code-review/SKILL.md +0 -213
  93. package/skills/requesting-code-review/SKILL.md +0 -105
  94. package/skills/requesting-code-review/code-reviewer.md +0 -146
  95. package/skills/rules/skill-map.md +0 -97
  96. package/skills/subagent-driven-development/SKILL.md +0 -277
  97. package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +0 -26
  98. package/skills/subagent-driven-development/implementer-prompt.md +0 -113
  99. package/skills/subagent-driven-development/spec-reviewer-prompt.md +0 -61
  100. package/skills/systematic-debugging/CREATION-LOG.md +0 -119
  101. package/skills/systematic-debugging/SKILL.md +0 -296
  102. package/skills/systematic-debugging/condition-based-waiting-example.ts +0 -158
  103. package/skills/systematic-debugging/condition-based-waiting.md +0 -115
  104. package/skills/systematic-debugging/defense-in-depth.md +0 -122
  105. package/skills/systematic-debugging/find-polluter.sh +0 -63
  106. package/skills/systematic-debugging/root-cause-tracing.md +0 -169
  107. package/skills/systematic-debugging/test-academic.md +0 -14
  108. package/skills/systematic-debugging/test-pressure-1.md +0 -58
  109. package/skills/systematic-debugging/test-pressure-2.md +0 -68
  110. package/skills/systematic-debugging/test-pressure-3.md +0 -69
  111. package/skills/test-driven-development/SKILL.md +0 -371
  112. package/skills/test-driven-development/testing-anti-patterns.md +0 -299
  113. package/skills/using-git-worktrees/SKILL.md +0 -218
  114. package/skills/using-superpowers/SKILL.md +0 -134
  115. package/skills/using-superpowers/references/codex-tools.md +0 -25
  116. package/skills/using-superpowers/references/gemini-tools.md +0 -33
  117. package/skills/verification-before-completion/SKILL.md +0 -139
  118. package/skills/workflow-runner/SKILL.md +0 -172
  119. package/skills/writing-plans/SKILL.md +0 -152
  120. package/skills/writing-plans/plan-document-reviewer-prompt.md +0 -49
  121. package/skills/writing-skills/SKILL.md +0 -654
  122. package/skills/writing-skills/anthropic-best-practices.md +0 -1149
  123. package/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +0 -189
  124. package/skills/writing-skills/graphviz-conventions.dot +0 -172
  125. package/skills/writing-skills/persuasion-principles.md +0 -187
  126. package/skills/writing-skills/render-graphs.js +0 -168
  127. package/skills/writing-skills/testing-skills-with-subagents.md +0 -384
@@ -1,371 +0,0 @@
1
- ---
2
- name: test-driven-development
3
- description: 在实现任何功能或修复 bug 时使用,在编写实现代码之前
4
- ---
5
-
6
- # 测试驱动开发(TDD)
7
-
8
- ## 概述
9
-
10
- 先写测试。看它失败。写最少的代码让它通过。
11
-
12
- **核心原则:** 如果你没有看到测试失败,你就不知道它是否测试了正确的东西。
13
-
14
- **违反规则的字面意思就是违反规则的精神。**
15
-
16
- ## 何时使用
17
-
18
- **始终使用:**
19
- - 新功能
20
- - Bug 修复
21
- - 重构
22
- - 行为变更
23
-
24
- **例外(需询问你的人类伙伴):**
25
- - 一次性原型
26
- - 生成的代码
27
- - 配置文件
28
-
29
- 想着"就这一次跳过 TDD"?停下来。那是在给自己找借口。
30
-
31
- ## 铁律
32
-
33
- ```
34
- 没有失败的测试,就不写生产代码
35
- ```
36
-
37
- 先写了代码再写测试?删掉它。从头来过。
38
-
39
- **没有例外:**
40
- - 不要保留作为"参考"
41
- - 不要在写测试时"改编"它
42
- - 不要看它
43
- - 删除就是删除
44
-
45
- 从测试出发,重新实现。句号。
46
-
47
- ## 红-绿-重构
48
-
49
- ```dot
50
- digraph tdd_cycle {
51
- rankdir=LR;
52
- red [label="红灯\n编写失败的测试", shape=box, style=filled, fillcolor="#ffcccc"];
53
- verify_red [label="验证正确失败", shape=diamond];
54
- green [label="绿灯\n最少代码", shape=box, style=filled, fillcolor="#ccffcc"];
55
- verify_green [label="验证通过\n全部绿灯", shape=diamond];
56
- refactor [label="重构\n清理代码", shape=box, style=filled, fillcolor="#ccccff"];
57
- next [label="下一个", shape=ellipse];
58
-
59
- red -> verify_red;
60
- verify_red -> green [label="是"];
61
- verify_red -> red [label="错误的\n失败"];
62
- green -> verify_green;
63
- verify_green -> refactor [label="是"];
64
- verify_green -> green [label="否"];
65
- refactor -> verify_green [label="保持\n绿灯"];
66
- verify_green -> next;
67
- next -> red;
68
- }
69
- ```
70
-
71
- ### 红灯 - 编写失败的测试
72
-
73
- 写一个最小的测试来展示期望行为。
74
-
75
- <Good>
76
- ```typescript
77
- test('retries failed operations 3 times', async () => {
78
- let attempts = 0;
79
- const operation = () => {
80
- attempts++;
81
- if (attempts < 3) throw new Error('fail');
82
- return 'success';
83
- };
84
-
85
- const result = await retryOperation(operation);
86
-
87
- expect(result).toBe('success');
88
- expect(attempts).toBe(3);
89
- });
90
- ```
91
- 名称清晰,测试真实行为,只测一件事
92
- </Good>
93
-
94
- <Bad>
95
- ```typescript
96
- test('retry works', async () => {
97
- const mock = jest.fn()
98
- .mockRejectedValueOnce(new Error())
99
- .mockRejectedValueOnce(new Error())
100
- .mockResolvedValueOnce('success');
101
- await retryOperation(mock);
102
- expect(mock).toHaveBeenCalledTimes(3);
103
- });
104
- ```
105
- 名称模糊,测试的是 mock 而非代码
106
- </Bad>
107
-
108
- **要求:**
109
- - 一个行为
110
- - 清晰的名称
111
- - 使用真实代码(除非不得已才用 mock)
112
-
113
- ### 验证红灯 - 看它失败
114
-
115
- **必须执行。绝不跳过。**
116
-
117
- ```bash
118
- npm test path/to/test.test.ts
119
- ```
120
-
121
- 确认:
122
- - 测试失败(不是报错)
123
- - 失败信息符合预期
124
- - 失败原因是功能缺失(不是拼写错误)
125
-
126
- **测试通过了?** 你在测试已有的行为。修改测试。
127
-
128
- **测试报错了?** 修复错误,重新运行直到它正确地失败。
129
-
130
- ### 绿灯 - 最少代码
131
-
132
- 写最简单的代码让测试通过。
133
-
134
- <Good>
135
- ```typescript
136
- async function retryOperation<T>(fn: () => Promise<T>): Promise<T> {
137
- for (let i = 0; i < 3; i++) {
138
- try {
139
- return await fn();
140
- } catch (e) {
141
- if (i === 2) throw e;
142
- }
143
- }
144
- throw new Error('unreachable');
145
- }
146
- ```
147
- 刚好够通过测试
148
- </Good>
149
-
150
- <Bad>
151
- ```typescript
152
- async function retryOperation<T>(
153
- fn: () => Promise<T>,
154
- options?: {
155
- maxRetries?: number;
156
- backoff?: 'linear' | 'exponential';
157
- onRetry?: (attempt: number) => void;
158
- }
159
- ): Promise<T> {
160
- // YAGNI
161
- }
162
- ```
163
- 过度设计
164
- </Bad>
165
-
166
- 不要添加功能、重构其他代码或做超出测试要求的"改进"。
167
-
168
- ### 验证绿灯 - 看它通过
169
-
170
- **必须执行。**
171
-
172
- ```bash
173
- npm test path/to/test.test.ts
174
- ```
175
-
176
- 确认:
177
- - 测试通过
178
- - 其他测试仍然通过
179
- - 输出干净(没有错误、警告)
180
-
181
- **测试失败了?** 修改代码,不是测试。
182
-
183
- **其他测试失败了?** 立即修复。
184
-
185
- ### 重构 - 清理代码
186
-
187
- 只有在绿灯之后才重构:
188
- - 消除重复
189
- - 改善命名
190
- - 提取辅助函数
191
-
192
- 保持测试绿灯。不要添加行为。
193
-
194
- ### 重复
195
-
196
- 为下一个功能写下一个失败的测试。
197
-
198
- ## 好的测试
199
-
200
- | 特质 | 好的 | 差的 |
201
- |------|------|------|
202
- | **最小化** | 只测一件事。名称中有"和"?拆分它。 | `test('validates email and domain and whitespace')` |
203
- | **清晰** | 名称描述行为 | `test('test1')` |
204
- | **展示意图** | 展示期望的 API | 掩盖了代码应该做什么 |
205
-
206
- ## 为什么顺序很重要
207
-
208
- **"我先写完再补测试来验证"**
209
-
210
- 后写的测试立即通过。立即通过什么也证明不了:
211
- - 可能测试了错误的东西
212
- - 可能测试的是实现而非行为
213
- - 可能遗漏了你忘掉的边界情况
214
- - 你从未看到它捕获 bug
215
-
216
- 先写测试迫使你看到测试失败,证明它确实在测试某些东西。
217
-
218
- **"我已经手动测试了所有边界情况"**
219
-
220
- 手动测试是临时的。你以为你测试了所有情况,但是:
221
- - 没有测试记录
222
- - 代码变更后无法重新运行
223
- - 在压力下容易遗忘
224
- - "我试过了能跑" 不等于 全面测试
225
-
226
- 自动化测试是系统性的。它们每次以相同方式运行。
227
-
228
- **"删除 X 小时的工作太浪费了"**
229
-
230
- 沉没成本谬误。时间已经花了。你现在的选择:
231
- - 删除并用 TDD 重写(再花 X 小时,高信心)
232
- - 保留并后补测试(30 分钟,低信心,可能有 bug)
233
-
234
- "浪费"的是保留你无法信任的代码。没有真正测试的可运行代码就是技术债。
235
-
236
- **"TDD 太教条了,务实意味着灵活变通"**
237
-
238
- TDD 就是务实的:
239
- - 在 commit 前发现 bug(比事后调试快)
240
- - 防止回归(测试立即发现破坏)
241
- - 记录行为(测试展示如何使用代码)
242
- - 支持重构(放心修改,测试捕获破坏)
243
-
244
- "务实的"捷径 = 在生产环境调试 = 更慢。
245
-
246
- **"后补测试也能达到相同目的——重要的是精神不是仪式"**
247
-
248
- 不对。后补测试回答"这段代码做了什么?"先写测试回答"这段代码应该做什么?"
249
-
250
- 后补测试受你实现的偏见影响。你测试的是你构建的东西,而非需求要求的。你验证的是你记得的边界情况,而非发现的。
251
-
252
- 先写测试迫使你在实现前发现边界情况。后补测试验证的是你记住了所有情况(你没有)。
253
-
254
- 30 分钟的后补测试 ≠ TDD。你得到了覆盖率,但失去了测试有效的证明。
255
-
256
- ## 常见借口
257
-
258
- | 借口 | 现实 |
259
- |------|------|
260
- | "太简单了不用测" | 简单的代码也会出 bug。测试只需 30 秒。 |
261
- | "我之后补测试" | 立即通过的测试什么也证明不了。 |
262
- | "后补测试也能达到相同目的" | 后补测试 = "这做了什么?" 先写测试 = "这应该做什么?" |
263
- | "已经手动测试过了" | 临时测试 ≠ 系统测试。无记录,无法重现。 |
264
- | "删除 X 小时的工作太浪费" | 沉没成本谬误。保留未验证的代码就是技术债。 |
265
- | "留作参考,然后先写测试" | 你会去改编它。那就是后补测试。删除就是删除。 |
266
- | "需要先探索一下" | 可以。探索完了扔掉,从 TDD 开始。 |
267
- | "测试难写 = 设计不清楚" | 听测试的。难以测试 = 难以使用。 |
268
- | "TDD 会拖慢我" | TDD 比调试快。务实 = 先写测试。 |
269
- | "手动测试更快" | 手动测试无法证明边界情况。每次修改你都得重新测。 |
270
- | "现有代码没有测试" | 你在改进它。为现有代码补测试。 |
271
-
272
- ## 危险信号 - 停下来,从头开始
273
-
274
- - 先写了代码再写测试
275
- - 实现完了才补测试
276
- - 测试立即通过
277
- - 无法解释测试为什么失败
278
- - "之后再补"测试
279
- - 说服自己"就这一次"
280
- - "我已经手动测试过了"
281
- - "后补测试也能达到相同目的"
282
- - "重要的是精神不是仪式"
283
- - "留作参考"或"改编现有代码"
284
- - "已经花了 X 小时了,删掉太浪费"
285
- - "TDD 太教条了,我是在务实"
286
- - "这次情况不同,因为……"
287
-
288
- **以上所有情况都意味着:删除代码。用 TDD 从头开始。**
289
-
290
- ## 示例:Bug 修复
291
-
292
- **Bug:** 空邮箱被接受了
293
-
294
- **红灯**
295
- ```typescript
296
- test('rejects empty email', async () => {
297
- const result = await submitForm({ email: '' });
298
- expect(result.error).toBe('Email required');
299
- });
300
- ```
301
-
302
- **验证红灯**
303
- ```bash
304
- $ npm test
305
- FAIL: expected 'Email required', got undefined
306
- ```
307
-
308
- **绿灯**
309
- ```typescript
310
- function submitForm(data: FormData) {
311
- if (!data.email?.trim()) {
312
- return { error: 'Email required' };
313
- }
314
- // ...
315
- }
316
- ```
317
-
318
- **验证绿灯**
319
- ```bash
320
- $ npm test
321
- PASS
322
- ```
323
-
324
- **重构**
325
- 如果需要,提取验证逻辑以支持多个字段。
326
-
327
- ## 验证清单
328
-
329
- 在标记工作完成之前:
330
-
331
- - [ ] 每个新函数/方法都有测试
332
- - [ ] 在实现之前看到每个测试失败
333
- - [ ] 每个测试因预期原因失败(功能缺失,不是拼写错误)
334
- - [ ] 为每个测试编写了最少代码使其通过
335
- - [ ] 所有测试通过
336
- - [ ] 输出干净(没有错误、警告)
337
- - [ ] 测试使用真实代码(只在不可避免时用 mock)
338
- - [ ] 覆盖了边界情况和错误场景
339
-
340
- 不能全部勾选?你跳过了 TDD。从头开始。
341
-
342
- ## 遇到困难时
343
-
344
- | 问题 | 解决方案 |
345
- |------|----------|
346
- | 不知道怎么测试 | 写出你期望的 API。先写断言。问你的人类伙伴。 |
347
- | 测试太复杂 | 设计太复杂。简化接口。 |
348
- | 必须 mock 所有东西 | 代码耦合太紧。使用依赖注入。 |
349
- | 测试 setup 太庞大 | 提取辅助函数。还是复杂?简化设计。 |
350
-
351
- ## 调试集成
352
-
353
- 发现 bug?写一个重现 bug 的失败测试。按 TDD 循环走。测试既证明了修复有效,又防止了回归。
354
-
355
- 绝不在没有测试的情况下修复 bug。
356
-
357
- ## 测试反模式
358
-
359
- 添加 mock 或测试工具时,阅读 @testing-anti-patterns.md 以避免常见陷阱:
360
- - 测试 mock 行为而非真实行为
361
- - 在生产类中添加仅测试用的方法
362
- - 在不理解依赖的情况下使用 mock
363
-
364
- ## 最终规则
365
-
366
- ```
367
- 生产代码 → 测试存在且先失败
368
- 否则 → 不是 TDD
369
- ```
370
-
371
- 没有你的人类伙伴的许可,没有例外。
@@ -1,299 +0,0 @@
1
- # 测试反模式
2
-
3
- **在以下情况加载此参考:** 编写或修改测试、添加 mock、或想在生产代码中添加仅测试用方法时。
4
-
5
- ## 概述
6
-
7
- 测试必须验证真实行为,而非 mock 行为。Mock 是隔离的手段,不是被测试的对象。
8
-
9
- **核心原则:** 测试代码做了什么,而非 mock 做了什么。
10
-
11
- **严格遵循 TDD 可以防止这些反模式。**
12
-
13
- ## 铁律
14
-
15
- ```
16
- 1. 绝不测试 mock 行为
17
- 2. 绝不在生产类中添加仅测试用的方法
18
- 3. 绝不在不理解依赖的情况下使用 mock
19
- ```
20
-
21
- ## 反模式 1:测试 Mock 行为
22
-
23
- **违规做法:**
24
- ```typescript
25
- // ❌ 差:测试 mock 是否存在
26
- test('renders sidebar', () => {
27
- render(<Page />);
28
- expect(screen.getByTestId('sidebar-mock')).toBeInTheDocument();
29
- });
30
- ```
31
-
32
- **为什么这是错误的:**
33
- - 你在验证 mock 能工作,而非组件能工作
34
- - mock 存在时测试通过,不存在时失败
35
- - 对真实行为一无所知
36
-
37
- **你的人类伙伴的纠正:** "我们是在测试 mock 的行为吗?"
38
-
39
- **正确做法:**
40
- ```typescript
41
- // ✅ 好:测试真实组件或不要 mock 它
42
- test('renders sidebar', () => {
43
- render(<Page />); // 不要 mock sidebar
44
- expect(screen.getByRole('navigation')).toBeInTheDocument();
45
- });
46
-
47
- // 或者如果必须 mock sidebar 来隔离:
48
- // 不要对 mock 做断言——测试 Page 在 sidebar 存在时的行为
49
- ```
50
-
51
- ### 门控函数
52
-
53
- ```
54
- 在对任何 mock 元素做断言之前:
55
- 问:"我是在测试真实组件行为还是仅仅测试 mock 的存在?"
56
-
57
- 如果是测试 mock 的存在:
58
- 停下——删除断言或取消 mock
59
-
60
- 改为测试真实行为
61
- ```
62
-
63
- ## 反模式 2:在生产代码中添加仅测试用方法
64
-
65
- **违规做法:**
66
- ```typescript
67
- // ❌ 差:destroy() 仅在测试中使用
68
- class Session {
69
- async destroy() { // 看起来像生产 API!
70
- await this._workspaceManager?.destroyWorkspace(this.id);
71
- // ... 清理
72
- }
73
- }
74
-
75
- // 在测试中
76
- afterEach(() => session.destroy());
77
- ```
78
-
79
- **为什么这是错误的:**
80
- - 生产类被仅测试用的代码污染
81
- - 如果在生产环境中意外调用会很危险
82
- - 违反 YAGNI 和关注点分离
83
- - 混淆了对象生命周期和实体生命周期
84
-
85
- **正确做法:**
86
- ```typescript
87
- // ✅ 好:测试工具处理测试清理
88
- // Session 没有 destroy()——它在生产中是无状态的
89
-
90
- // 在 test-utils/ 中
91
- export async function cleanupSession(session: Session) {
92
- const workspace = session.getWorkspaceInfo();
93
- if (workspace) {
94
- await workspaceManager.destroyWorkspace(workspace.id);
95
- }
96
- }
97
-
98
- // 在测试中
99
- afterEach(() => cleanupSession(session));
100
- ```
101
-
102
- ### 门控函数
103
-
104
- ```
105
- 在向生产类添加任何方法之前:
106
- 问:"这只被测试使用吗?"
107
-
108
- 如果是:
109
- 停下——不要添加
110
- 放到测试工具中
111
-
112
- 问:"这个类是否拥有此资源的生命周期?"
113
-
114
- 如果否:
115
- 停下——这个方法不属于这个类
116
- ```
117
-
118
- ## 反模式 3:不理解依赖就使用 Mock
119
-
120
- **违规做法:**
121
- ```typescript
122
- // ❌ 差:Mock 破坏了测试逻辑
123
- test('detects duplicate server', () => {
124
- // Mock 阻止了测试依赖的配置写入!
125
- vi.mock('ToolCatalog', () => ({
126
- discoverAndCacheTools: vi.fn().mockResolvedValue(undefined)
127
- }));
128
-
129
- await addServer(config);
130
- await addServer(config); // 应该抛异常——但不会!
131
- });
132
- ```
133
-
134
- **为什么这是错误的:**
135
- - 被 mock 的方法有测试依赖的副作用(写入配置)
136
- - "保险起见"过度 mock 破坏了实际行为
137
- - 测试因错误的原因通过或莫名其妙地失败
138
-
139
- **正确做法:**
140
- ```typescript
141
- // ✅ 好:在正确的层级 mock
142
- test('detects duplicate server', () => {
143
- // Mock 慢的部分,保留测试需要的行为
144
- vi.mock('MCPServerManager'); // 只 mock 慢的服务器启动
145
-
146
- await addServer(config); // 配置被写入
147
- await addServer(config); // 检测到重复 ✓
148
- });
149
- ```
150
-
151
- ### 门控函数
152
-
153
- ```
154
- 在 mock 任何方法之前:
155
- 停下——先不要 mock
156
-
157
- 1. 问:"真实方法有什么副作用?"
158
- 2. 问:"这个测试是否依赖这些副作用?"
159
- 3. 问:"我完全理解这个测试需要什么吗?"
160
-
161
- 如果依赖副作用:
162
- 在更底层 mock(实际的慢操作/外部操作)
163
- 或使用保留必要行为的测试替身
164
- 而非测试依赖的高层方法
165
-
166
- 如果不确定测试依赖什么:
167
- 先用真实实现运行测试
168
- 观察实际需要发生什么
169
- 然后在正确的层级添加最少的 mock
170
-
171
- 危险信号:
172
- - "我 mock 一下保险"
173
- - "这可能慢,还是 mock 掉吧"
174
- - 不理解依赖链就 mock
175
- ```
176
-
177
- ## 反模式 4:不完整的 Mock
178
-
179
- **违规做法:**
180
- ```typescript
181
- // ❌ 差:部分 mock——只包含你认为需要的字段
182
- const mockResponse = {
183
- status: 'success',
184
- data: { userId: '123', name: 'Alice' }
185
- // 缺失:下游代码使用的 metadata
186
- };
187
-
188
- // 之后:代码访问 response.metadata.requestId 时崩溃
189
- ```
190
-
191
- **为什么这是错误的:**
192
- - **部分 mock 隐藏了结构假设** — 你只 mock 了你知道的字段
193
- - **下游代码可能依赖你没包含的字段** — 静默失败
194
- - **测试通过但集成失败** — mock 不完整,真实 API 完整
195
- - **虚假的信心** — 测试对真实行为什么也没证明
196
-
197
- **铁律:** Mock 真实存在的完整数据结构,而非只包含你当前测试用到的字段。
198
-
199
- **正确做法:**
200
- ```typescript
201
- // ✅ 好:镜像真实 API 的完整性
202
- const mockResponse = {
203
- status: 'success',
204
- data: { userId: '123', name: 'Alice' },
205
- metadata: { requestId: 'req-789', timestamp: 1234567890 }
206
- // 真实 API 返回的所有字段
207
- };
208
- ```
209
-
210
- ### 门控函数
211
-
212
- ```
213
- 在创建 mock 响应之前:
214
- 检查:"真实 API 响应包含哪些字段?"
215
-
216
- 操作:
217
- 1. 从文档/示例中查看实际 API 响应
218
- 2. 包含系统下游可能消费的所有字段
219
- 3. 验证 mock 完全匹配真实响应的结构
220
-
221
- 关键:
222
- 如果你在创建 mock,你必须理解完整的结构
223
- 部分 mock 在代码依赖遗漏字段时会静默失败
224
-
225
- 不确定时:包含所有文档记录的字段
226
- ```
227
-
228
- ## 反模式 5:集成测试作为事后补充
229
-
230
- **违规做法:**
231
- ```
232
- ✅ 实现完成
233
- ❌ 没写测试
234
- "准备好测试了"
235
- ```
236
-
237
- **为什么这是错误的:**
238
- - 测试是实现的一部分,不是可选的后续
239
- - TDD 本可以防止这种情况
240
- - 没有测试就不能声称完成
241
-
242
- **正确做法:**
243
- ```
244
- TDD 循环:
245
- 1. 编写失败的测试
246
- 2. 实现使其通过
247
- 3. 重构
248
- 4. 然后才声称完成
249
- ```
250
-
251
- ## 当 Mock 变得过于复杂时
252
-
253
- **警告信号:**
254
- - Mock 的 setup 比测试逻辑还长
255
- - 为了让测试通过而 mock 一切
256
- - Mock 缺少真实组件拥有的方法
257
- - Mock 变更时测试就坏了
258
-
259
- **你的人类伙伴的问题:** "我们这里真的需要用 mock 吗?"
260
-
261
- **考虑:** 使用真实组件的集成测试往往比复杂的 mock 更简单
262
-
263
- ## TDD 如何防止这些反模式
264
-
265
- **TDD 有帮助的原因:**
266
- 1. **先写测试** → 迫使你思考你到底在测什么
267
- 2. **看它失败** → 确认测试测的是真实行为,不是 mock
268
- 3. **最少实现** → 仅测试用方法不会混入
269
- 4. **真实依赖** → 你在 mock 之前看到测试实际需要什么
270
-
271
- **如果你在测试 mock 行为,你违反了 TDD** — 你在没有先用真实代码让测试失败的情况下就加了 mock。
272
-
273
- ## 快速参考
274
-
275
- | 反模式 | 修复方式 |
276
- |--------|----------|
277
- | 对 mock 元素做断言 | 测试真实组件或取消 mock |
278
- | 生产代码中的仅测试用方法 | 移到测试工具中 |
279
- | 不理解就 mock | 先理解依赖,最少 mock |
280
- | 不完整的 mock | 完整镜像真实 API |
281
- | 测试作为事后补充 | TDD——先写测试 |
282
- | 过于复杂的 mock | 考虑集成测试 |
283
-
284
- ## 危险信号
285
-
286
- - 断言检查 `*-mock` test ID
287
- - 方法仅在测试文件中被调用
288
- - Mock setup 占测试的 >50%
289
- - 移除 mock 测试就失败
290
- - 无法解释为什么需要 mock
291
- - "保险起见" mock 掉
292
-
293
- ## 底线
294
-
295
- **Mock 是隔离的工具,不是被测试的对象。**
296
-
297
- 如果 TDD 揭示你在测试 mock 行为,你已经走偏了。
298
-
299
- 修复方法:测试真实行为,或质疑为什么要 mock。