kld-sdd 2.6.1 → 2.6.2

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 (62) hide show
  1. package/package.json +1 -1
  2. package/templates/skills/kld-sdd/opsx-apply/SKILL.md +28 -21
  3. package/templates/skills/kld-sdd/opsx-apply/checklist.md +36 -30
  4. package/templates/skills/kld-sdd/opsx-apply/implementer-prompt.md +27 -31
  5. package/templates/skills/kld-sdd/opsx-apply/reference.md +7 -38
  6. package/templates/skills/kld-sdd/opsx-check/SKILL.md +8 -11
  7. package/templates/skills/kld-sdd/opsx-check/checklist.md +4 -10
  8. package/templates/skills/kld-sdd/opsx-design/SKILL.md +2 -0
  9. package/templates/skills/kld-sdd/opsx-design/checklist.md +1 -0
  10. package/templates/skills/kld-sdd/opsx-propose/reference.md +8 -18
  11. package/templates/skills/kld-sdd/opsx-rules/reference.md +1 -1
  12. package/templates/skills/kld-sdd/opsx-spec/SKILL.md +2 -0
  13. package/templates/skills/kld-sdd/opsx-task/SKILL.md +26 -43
  14. package/templates/skills/kld-sdd/opsx-task/checklist.md +4 -10
  15. package/templates/skills/kld-sdd/opsx-task/reference.md +12 -6
  16. package/templates/skills/kld-sdd/opsx-tdd-anti-patterns/SKILL.md +79 -0
  17. package/templates/skills/kld-sdd/opsx-tdd-anti-patterns/reference.md +203 -0
  18. package/templates/skills/kld-sdd/opsx-tdd-core/SKILL.md +167 -0
  19. package/templates/skills/kld-sdd/opsx-tdd-core/checklist.md +55 -0
  20. package/templates/skills/kld-sdd/opsx-tdd-core/reference.md +146 -0
  21. package/templates/skills/kld-sdd/opsx-tdd-metrics/SKILL.md +73 -0
  22. package/templates/skills/kld-sdd/opsx-tdd-metrics/checklist.md +60 -0
  23. package/templates/skills/kld-sdd/opsx-tdd-quality/SKILL.md +95 -0
  24. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/general/cause-effect-clarity.md +19 -0
  25. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/general/clean-test-data.md +33 -0
  26. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/general/existing-test-awareness.md +17 -0
  27. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/general/given-when-then.md +44 -0
  28. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/general/good-test-qualities.md +32 -0
  29. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/general/mock-boundary.md +44 -0
  30. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/general/naming-conventions.md +37 -0
  31. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/general/no-logic-in-tests.md +30 -0
  32. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/general/one-test-one-scenario.md +23 -0
  33. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/general/parameterized-testing.md +56 -0
  34. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/general/prefer-public-apis.md +17 -0
  35. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/general/test-behaviors-not-methods.md +26 -0
  36. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/java/argument-matching.md +38 -0
  37. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/java/controller-test-rules.md +37 -0
  38. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/java/domain-service-rules.md +33 -0
  39. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/java/java-test-template.md +42 -0
  40. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/java/json-serialization.md +34 -0
  41. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/java/logging-rules.md +35 -0
  42. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/post-generation/compilation-verification.md +25 -0
  43. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/post-generation/execution-verification.md +28 -0
  44. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/python/py-test-template.md +40 -0
  45. package/templates/skills/kld-sdd/opsx-tdd-quality/rules/typescript/ts-test-template.md +45 -0
  46. package/templates/skills/kld-sdd/opsx-tdd-review/SKILL.md +66 -0
  47. package/templates/skills/kld-sdd/opsx-tdd-review/checklist.md +39 -0
  48. package/templates/skills/kld-sdd/opsx-tdd-rules/SKILL.md +29 -0
  49. package/templates/skills/kld-sdd/opsx-tdd-rules/rules/controller-strategy.md +32 -0
  50. package/templates/skills/kld-sdd/opsx-tdd-rules/rules/dag-generation-rules.md +20 -0
  51. package/templates/skills/kld-sdd/opsx-tdd-rules/rules/des-step-annotation.md +36 -0
  52. package/templates/skills/kld-sdd/opsx-tdd-rules/rules/exception-path-coverage.md +47 -0
  53. package/templates/skills/kld-sdd/opsx-tdd-rules/rules/green-scope-declaration.md +45 -0
  54. package/templates/skills/kld-sdd/opsx-tdd-rules/rules/green-yagni-fence.md +41 -0
  55. package/templates/skills/kld-sdd/opsx-tdd-rules/rules/multi-validation-split.md +36 -0
  56. package/templates/skills/kld-sdd/opsx-tdd-rules/rules/non-tdd-modules.md +17 -0
  57. package/templates/skills/kld-sdd/opsx-tdd-rules/rules/refactor-checklist.md +45 -0
  58. package/templates/skills/kld-sdd/opsx-tdd-rules/rules/task-type-definitions.md +23 -0
  59. package/templates/skills/kld-sdd/opsx-tdd-rules/rules/tdd-strategy-selection.md +13 -0
  60. package/templates/skills/kld-sdd/opsx-tdd-rules/rules/test-execution-gate.md +25 -0
  61. package/templates/skills/kld-sdd/opsx-tdd-rules/rules/test-skeleton-telemetry.md +19 -0
  62. package/templates/skills/kld-sdd/opsx-test/SKILL.md +4 -3
@@ -18,6 +18,8 @@ description: opsx-task 的详细模板:telemetry 命令、DAG 生成规则表
18
18
 
19
19
  ## §6 DAG 生成规则表
20
20
 
21
+ > 完整规则见 `opsx-tdd-rules/rules/dag-generation-rules.md`,此处仅保留快速参考。
22
+
21
23
  **根据 test-strategy 调整 DAG 生成规则:**
22
24
 
23
25
  | test-strategy | DAG 生成规则 |
@@ -37,19 +39,21 @@ spec.md user-auth 定义了 7 个场景,拆为 7 对 RED+GREEN + 1 个 REFACTO
37
39
  | 任务 ID | 行为点 | 类型 | 依赖 | 验收标准 |
38
40
  |---------|--------|------|------|---------|
39
41
  | TASK-05-RED-1 | 登录成功返回 Token | 测试-RED | TASK-04-IMPL | 测试带断言运行失败,失败原因:AuthService 未实现 |
40
- | TASK-05-GREEN-1 | 登录成功最小实现 | 实现-GREEN | TASK-05-RED-1 | 写最少代码让 RED-1 通过,不提前实现密码校验等 |
42
+ | TASK-05-GREEN-1 | 登录成功最小实现 | 实现-GREEN | TASK-05-RED-1 | 写最少代码让 RED-1 通过。不提前实现密码校验(RED-2 的行为),仅让当前 RED 测试通过。 |
41
43
  | TASK-05-RED-2 | 密码错误返回 2001 | 测试-RED | TASK-05-GREEN-1 | 测试失败,失败原因:未校验密码 |
42
- | TASK-05-GREEN-2 | 密码校验实现 | 实现-GREEN | TASK-05-RED-2 | 让 RED-2 通过 |
44
+ | TASK-05-GREEN-2 | 密码校验实现 | 实现-GREEN | TASK-05-RED-2 | 让 RED-2 通过。不提前实现账号状态校验(RED-3 的行为),仅让当前 RED 测试通过。 |
43
45
  | TASK-05-RED-3 | 账号禁用返回 2002 | 测试-RED | TASK-05-GREEN-2 | 测试失败 |
44
- | TASK-05-GREEN-3 | 账号状态校验 | 实现-GREEN | TASK-05-RED-3 | 让 RED-3 通过 |
46
+ | TASK-05-GREEN-3 | 账号状态校验 | 实现-GREEN | TASK-05-RED-3 | 让 RED-3 通过。不提前实现 Refresh Token(RED-4 的行为),仅让当前 RED 测试通过。 |
45
47
  | TASK-05-RED-4 | Refresh Token 有效 | 测试-RED | TASK-05-GREEN-3 | 测试失败 |
46
- | TASK-05-GREEN-4 | Refresh 实现 | 实现-GREEN | TASK-05-RED-4 | 让 RED-4 通过 |
48
+ | TASK-05-GREEN-4 | Refresh 实现 | 实现-GREEN | TASK-05-RED-4 | 让 RED-4 通过。不提前实现 Refresh Token 无效校验(RED-5 的行为),仅让当前 RED 测试通过。 |
47
49
  | TASK-05-RED-5 | Refresh Token 无效返回 3001 | 测试-RED | TASK-05-GREEN-4 | 测试失败 |
48
- | TASK-05-GREEN-5 | Refresh 校验实现 | 实现-GREEN | TASK-05-RED-5 | 让 RED-5 通过 |
50
+ | TASK-05-GREEN-5 | Refresh 校验实现 | 实现-GREEN | TASK-05-RED-5 | 让 RED-5 通过。不提前实现登出功能(RED-6 的行为),仅让当前 RED 测试通过。 |
49
51
  | TASK-05-RED-6 | 登出加入黑名单 | 测试-RED | TASK-05-GREEN-5 | 测试失败 |
50
- | TASK-05-GREEN-6 | 登出实现 | 实现-GREEN | TASK-05-RED-6 | 让 RED-6 通过 |
52
+ | TASK-05-GREEN-6 | 登出实现 | 实现-GREEN | TASK-05-RED-6 | 让 RED-6 通过。仅实现当前 RED 测试覆盖的行为路径,不提前实现后续 capability 的功能。 |
51
53
  | TASK-05-REFACTOR | 重构优化 | 重构-REFACTOR | TASK-05-GREEN-6 | 所有测试仍绿,代码清理 |
52
54
 
55
+ > GREEN 任务的 YAGNI 围栏生成规则详见 `opsx-tdd-rules/rules/green-yagni-fence.md`
56
+
53
57
  **关键区别**:
54
58
  - 每个 RED 任务都带**真实断言**,跑起来确实失败
55
59
  - 每个 GREEN 任务只写**让当前测试通过的最少代码**
@@ -81,6 +85,8 @@ spec.md user-auth 定义了 7 个场景,拆为 7 对 RED+GREEN + 1 个 REFACTO
81
85
 
82
86
  ## §6.2 非 TDD 模块处理规则
83
87
 
88
+ > 完整规则见 `opsx-tdd-rules/rules/non-tdd-modules.md`,此处仅保留快速参考。
89
+
84
90
  以下模块不需要红绿循环,按常规任务处理:
85
91
  - 前端 UI 页面(Vue 组件)→ UI层任务
86
92
  - 项目脚手架/配置(pom.xml, application.yml)→ 配置任务
@@ -0,0 +1,79 @@
1
+ ---
2
+ name: opsx-tdd-anti-patterns
3
+ description: "测试反模式防护层 — 15 种反模式检测(RED 阶段 3 种 + GREEN 后 12 种),每种带门禁函数和修复方案。当编写或审查测试代码时引用本技能。"
4
+ ---
5
+
6
+ # opsx-tdd-anti-patterns — 反模式防护层
7
+
8
+ > **定位**:测试反模式的系统化检测,RED 阶段 + GREEN 后双重检查。
9
+ > **参考来源**:Superpowers `testing-anti-patterns.md`
10
+
11
+ ---
12
+
13
+ ## §1 核心原则
14
+
15
+ > 测试必须验证真实行为,而非 mock 行为。Mock 是隔离的手段,不是被测试的对象。
16
+
17
+ > 遵循严格 TDD 可以防止这些反模式。
18
+
19
+ ## §2 三条铁律
20
+
21
+ 1. **NEVER test mock behavior** — 永远不要测试 mock 行为
22
+ 2. **NEVER add test-only methods to production classes** — 永远不要向生产类添加测试专用方法
23
+ 3. **NEVER mock without understanding dependencies** — 永远不要在不理解依赖的情况下 mock
24
+
25
+ ## §3 RED 阶段反模式(3 种)
26
+
27
+ ⛔ RED 阶段就必须检查,不要等到 GREEN 之后才发现测试是假的。
28
+
29
+ | # | 反模式 | 问题表现 | 门禁函数 | 修复方案 |
30
+ |---|--------|---------|---------|---------|
31
+ | 1 | **Mock 被测行为本身** | `when(jwtUtil.parseToken("invalid")).thenThrow(...)` — mock 了被测行为(解析失败),GREEN 只需加 try-catch | "我在测试真实组件行为还是仅测试 mock 存在?" | 使用真实 JwtUtil + 真实 invalid token,让解析自然失败 |
32
+ | 2 | **Mock 预定结论而非准备条件** | `when(bookMapper.countByPublisher(1L)).thenReturn(3)` 后只测 `if (count > 0) throw` — trivial 逻辑 | "我的测试是在验证完整行为链路,还是只验证一个 if 分支?" | Mock 边界依赖(Mapper)是合理的,但测试断言应验证完整行为链路(如 verify 不会执行 delete) |
33
+ | 3 | **Given 不是真实输入** | mock 出"这个输入会导致什么结果",而非传入真实数据让被测代码自行处理 | "我的 Given 是真实数据还是 mock 出的预定结论?" | 传入真实数据(如 `"invalid"` 字符串、`null`、空对象),让被测代码自行决定结果 |
34
+
35
+ ## §4 GREEN 后反模式(12 种)
36
+
37
+ | # | 反模式 | 问题表现 | 修复方案 |
38
+ |---|--------|---------|---------|
39
+ | 4 | **测试 mock 行为而非真实行为** | 测试验证的是 mock 被调用,而非真实业务逻辑 | 测试应验证输出/状态变化,而非方法调用 |
40
+ | 5 | **生产类中加测试专用方法** | 为方便测试在生产类中加了 public/protected 方法 | 通过公共 API 测试,不加测试专用方法 |
41
+ | 6 | **不理解依赖就 mock** | mock 了不理解的依赖,隐藏了结构假设 | 先理解依赖的职责再决定是否 mock |
42
+ | 7 | **不完整的 mock** | partial mock 隐藏了对象间的结构关系 | 要么完整 mock,要么用真实对象 |
43
+ | 8 | **集成测试作为事后补充** | 单元测试不足,用集成测试弥补 | 每个行为点应有独立的单元测试 |
44
+ | 9 | **测试通过但无真实断言** | 测试只有 `assertTrue(true)` 或无断言 | 测试必须有真实断言(assertNotNull/assertEquals/assertThrows/verify) |
45
+ | 10 | **过度 mock** | 单个测试 mock 了 >5 个依赖,测试脆弱且难以维护 | 减少依赖数量,或拆分为多个聚焦的测试 |
46
+ | 11 | **测试间隐式依赖** | 测试 B 依赖测试 A 的副作用(如数据库状态残留) | 每个测试自包含,`@BeforeEach` 重置状态 |
47
+ | 12 | **测试代码重复** | 大量 copy-paste 的测试代码,缺少 helper 提取 | 提取 test fixture builder 或 helper 方法 |
48
+ | 13 | **魔法值** | 测试中使用未解释的字面值(如 `assertEquals(42, result)` 无注释说明 42 的含义) | 使用命名常量或注释解释字面值含义 |
49
+ | 14 | **断言不足** | 只断言了部分结果,遗漏了关键属性(如只 assertNotNull 但不 assertEquals 具体值) | 每个测试至少有一个具体值断言(assertEquals),而非仅 assertNotNull |
50
+ | 15 | **缺少负面测试** | 只测试正常路径,不测试错误条件 | 每个方法至少有一个异常路径测试(见 `opsx-tdd-rules/rules/exception-path-coverage.md`) |
51
+
52
+ ## §5 门禁函数
53
+
54
+ 每种反模式对应一个自检问题,在编写测试时强制自问:
55
+
56
+ ```
57
+ BEFORE 编写测试代码:
58
+ 1. "我在测试真实组件行为还是仅测试 mock 存在?" → 如果仅测试 mock 存在,停止
59
+ 2. "我的 Given 是真实数据还是 mock 出的预定结论?" → 如果是预定结论,重写
60
+ 3. "我是否完全理解被 mock 依赖的副作用?" → 如果不理解,先理解再 mock
61
+ ```
62
+
63
+ ## §6 红旗列表
64
+
65
+ 以下信号出现时,测试可能存在反模式:
66
+
67
+ - 断言检查 `*-mock` 测试 ID
68
+ - 仅在测试文件中调用的方法
69
+ - Mock 设置占测试的 >50%
70
+ - 移除 mock 后测试失败
71
+ - 无法解释为什么需要 mock
72
+ - "为了安全"而 mock
73
+ - 测试立即通过(RED 阶段)
74
+ - 无法解释测试为何失败
75
+ - 单个测试 mock >5 个依赖
76
+ - 测试方法名包含 "and"(多行为混合)
77
+ - 测试中只有 `assertNotNull` 无具体值断言
78
+ - 测试中存在未解释的魔法数字/字符串
79
+ - 正常路径有测试但异常路径无测试
@@ -0,0 +1,203 @@
1
+ ---
2
+ description: "opsx-tdd-anti-patterns 详细参考 — 9 种反模式完整详表 + 修复方案代码示例。仅在需要详细反模式检查时读取。"
3
+ ---
4
+
5
+ # opsx-tdd-anti-patterns — 详细参考
6
+
7
+ > 仅在需要详细反模式检查时读取。日常检查见 `SKILL.md`。
8
+
9
+ ---
10
+
11
+ ## 反模式 1:Mock 被测行为本身
12
+
13
+ **问题**:验证 mock 是否存在,而非组件是否正常工作。
14
+
15
+ **反例**:
16
+ ```java
17
+ @Mock
18
+ private JwtUtil jwtUtil;
19
+
20
+ @Test
21
+ void refresh_invalidToken_returns3001() {
22
+ when(jwtUtil.parseToken("invalid")).thenThrow(new RuntimeException());
23
+ // GREEN 只需加 try-catch 就通过,测试无意义
24
+ assertThrows(BusinessException.class, () -> authService.refresh("invalid"));
25
+ }
26
+ ```
27
+
28
+ **正例**:
29
+ ```java
30
+ private JwtUtil jwtUtil; // 真实实例
31
+
32
+ @BeforeEach
33
+ void setUp() {
34
+ jwtUtil = new JwtUtil("real-secret-key-at-least-256-bits-long", 7200, 604800);
35
+ authService = new AuthService(userMapper, jwtUtil);
36
+ }
37
+
38
+ @Test
39
+ void refresh_invalidToken_returns3001() {
40
+ // 传入真实无效 token,让 JwtUtil.parseToken 自然抛异常
41
+ assertThrows(BusinessException.class, () -> authService.refresh("invalid-token-string"));
42
+ }
43
+ ```
44
+
45
+ ## 反模式 2:Mock 预定结论而非准备条件
46
+
47
+ **问题**:mock 出期望的中间结果,测试只验证 trivial 逻辑。
48
+
49
+ **反例**:
50
+ ```java
51
+ when(bookMapper.countByPublisher(1L)).thenReturn(3);
52
+ publisherService.delete(1L);
53
+ // 只测了 if (count > 0) throw,trivial 逻辑
54
+ ```
55
+
56
+ **正例**:
57
+ ```java
58
+ when(bookMapper.countByPublisher(1L)).thenReturn(3);
59
+ assertThrows(BusinessException.class, () -> publisherService.delete(1L));
60
+ // 验证完整行为链路:抛异常且不执行 delete
61
+ verify(publisherMapper, never()).update(any());
62
+ ```
63
+
64
+ ## 反模式 3:Given 不是真实输入
65
+
66
+ **问题**:mock 出"这个输入会导致什么结果",而非传入真实数据。
67
+
68
+ **反例**:
69
+ ```java
70
+ when(parseToken("invalid")).thenThrow(); // 预定了"invalid 会导致抛异常"这个结论
71
+ ```
72
+
73
+ **正例**:
74
+ ```java
75
+ // 传入 "invalid" 字符串,让真实的 parseToken 自行决定是否失败
76
+ authService.refresh("invalid");
77
+ ```
78
+
79
+ ## 反模式 4:测试 mock 行为而非真实行为
80
+
81
+ **问题**:测试验证的是 mock 被调用,而非真实业务逻辑。
82
+
83
+ **反例**:
84
+ ```java
85
+ verify(jwtUtil).parseToken(any()); // 只验证 mock 被调用
86
+ ```
87
+
88
+ **正例**:
89
+ ```java
90
+ assertNotNull(result.getAccessToken()); // 验证输出/状态变化
91
+ ```
92
+
93
+ ## 反模式 5:生产类中加测试专用方法
94
+
95
+ **问题**:为方便测试在生产类中加了 public/protected 方法。
96
+
97
+ **修复**:通过公共 API 测试,不加测试专用方法。如果需要测试内部逻辑,提取为独立类。
98
+
99
+ ## 反模式 6:不理解依赖就 mock
100
+
101
+ **问题**:mock 了不理解的依赖,隐藏了结构假设。
102
+
103
+ **门禁函数**:在 mock 任何方法之前,先问三个问题:
104
+ 1. "真实方法有什么副作用?"
105
+ 2. "此测试是否依赖这些副作用?"
106
+ 3. "我是否完全理解此测试需要什么?"
107
+
108
+ ## 反模式 7:不完整的 mock
109
+
110
+ **问题**:partial mock 隐藏了结构假设,下游代码可能依赖未包含的字段。
111
+
112
+ **铁律**:Mock 完整的数据结构,如同现实中存在的那样。
113
+
114
+ ## 反模式 8:集成测试作为事后补充
115
+
116
+ **问题**:测试是实现的一部分,不是可选的后续步骤。
117
+
118
+ **修复**:TDD 循环——写失败测试 → 实现通过 → 重构 → 然后声称完成。
119
+
120
+ ## 反模式 9:测试通过但无真实断言
121
+
122
+ **问题**:测试只有 `assertTrue(true)` 或无断言。
123
+
124
+ **修复**:测试必须有真实断言(assertNotNull/assertEquals/assertThrows/verify)。
125
+
126
+ ## 反模式 10:过度 mock
127
+
128
+ **问题**:单个测试 mock 了 >5 个依赖,测试脆弱且难以维护。
129
+
130
+ **反例**:
131
+ ```java
132
+ @Mock private UserMapper userMapper;
133
+ @Mock private BookMapper bookMapper;
134
+ @Mock private PublisherMapper publisherMapper;
135
+ @Mock private AuthorMapper authorMapper;
136
+ @Mock private CategoryMapper categoryMapper;
137
+ @Mock private BorrowMapper borrowMapper;
138
+ // 6 个 mock,测试脆弱
139
+ ```
140
+
141
+ **修复**:减少依赖数量,或拆分为多个聚焦的测试。考虑使用真实对象替代部分 mock。
142
+
143
+ ## 反模式 11:测试间隐式依赖
144
+
145
+ **问题**:测试 B 依赖测试 A 的副作用(如数据库状态残留)。
146
+
147
+ **反例**:
148
+ ```java
149
+ @Test void testA() { repository.save(user); }
150
+ @Test void testB() { assertEquals(1, repository.count()); } // 依赖 testA 的 save
151
+ ```
152
+
153
+ **修复**:每个测试自包含,`@BeforeEach` 重置状态。
154
+
155
+ ## 反模式 12:测试代码重复
156
+
157
+ **问题**:大量 copy-paste 的测试代码,缺少 helper 提取。
158
+
159
+ **修复**:提取 test fixture builder 或 helper 方法。
160
+
161
+ ## 反模式 13:魔法值
162
+
163
+ **问题**:测试中使用未解释的字面值。
164
+
165
+ **反例**:
166
+ ```java
167
+ assertEquals(42, result); // 42 是什么?
168
+ ```
169
+
170
+ **正例**:
171
+ ```java
172
+ int expectedAvailableCount = 2; // total=3, borrowed=1, so available=2
173
+ assertEquals(expectedAvailableCount, result);
174
+ ```
175
+
176
+ ## 反模式 14:断言不足
177
+
178
+ **问题**:只断言了部分结果,遗漏了关键属性。
179
+
180
+ **反例**:
181
+ ```java
182
+ assertNotNull(result); // 弱断言,不验证具体值
183
+ ```
184
+
185
+ **正例**:
186
+ ```java
187
+ assertNotNull(result);
188
+ assertEquals("borrowed", result.getStatus());
189
+ assertEquals("user-001", result.getUserId());
190
+ ```
191
+
192
+ ## 反模式 15:缺少负面测试
193
+
194
+ **问题**:只测试正常路径,不测试错误条件。
195
+
196
+ **修复**:每个方法至少有一个异常路径测试。规则见 `opsx-tdd-rules/rules/exception-path-coverage.md`。
197
+
198
+ ## TDD 如何防止这些反模式
199
+
200
+ 1. 先写测试 → 迫使你思考实际在测试什么
201
+ 2. 看它失败 → 确认测试测试的是真实行为,不是 mock
202
+ 3. 最小实现 → 不会出现测试专用方法
203
+ 4. 真实依赖 → 在 mock 之前看到测试实际需要什么
@@ -0,0 +1,167 @@
1
+ ---
2
+ name: opsx-tdd-core
3
+ description: "TDD 流程纪律层 — 铁律、红绿重构循环、执行门禁、合规自检。当 test-strategy=tdd 时,所有 SDD 阶段引用本技能获取 TDD 流程规则。"
4
+ ---
5
+
6
+ # opsx-tdd-core — TDD 流程纪律层
7
+
8
+ > **定位**:TDD 铁律、红绿重构循环定义、执行门禁的唯一真相源。
9
+ > **参考来源**:Superpowers `test-driven-development`
10
+
11
+ ---
12
+
13
+ ## §1 铁律
14
+
15
+ ```
16
+ NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
17
+ ```
18
+
19
+ - 先写了生产代码再写测试?删除它,从测试开始
20
+ - "太简单不用测" → 如果值得写,就值得测
21
+ - "事后补测一样" → 不一样,TDD 的价值在于测试驱动设计
22
+ - "删了浪费" → 删掉重来比带着错误前提实现更省时间
23
+ - "保留作参考" → 你会改编它,那就是后写测试,删除就是删除
24
+
25
+ ## §2 基础原则
26
+
27
+ > 违反规则的字面意义就是违反规则的精神。
28
+
29
+ ## §3 红绿重构循环
30
+
31
+ ```
32
+ RED → Verify RED → 🔴中断声明 → GREEN → Verify GREEN → GREEN Scope 门禁 → REFACTOR → Repeat
33
+ ```
34
+
35
+ > **⛔ 严格串行**:RED→GREEN 对不可并行、不可批量。每个 RED 必须先确认失败,再进入 GREEN;每个 GREEN 必须先通过 Scope 门禁,再进入下一个 RED。禁止"看到全貌后一次性实现多个行为点"。
36
+
37
+ - **RED**:写一个最小的失败测试,展示期望行为
38
+ - 一个行为、清晰名称、真实代码(除非不可避免否则不用 mock)
39
+ - ⛔ **只写当前 RED 对应的测试方法**,不提前写后续 RED 的测试
40
+ - **Verify RED**(强制执行,绝不跳过):
41
+ - 确认测试失败(不是报错)
42
+ - 失败信息符合预期
43
+ - 因功能缺失而失败(不是拼写错误)
44
+ - 测试通过?说明在测试已有行为,修复测试
45
+ - 测试报错?修复错误,重新运行直到正确失败
46
+ - **🔴 中断声明**(强制执行,绝不跳过):
47
+ - RED 确认失败后,必须显式声明中断点:
48
+ `🔴 RED-N 确认失败,原因:[具体原因]。现在进入 GREEN-N,仅实现让此测试通过的最少代码。`
49
+ - 此声明强制 agent 在 RED 和 GREEN 之间产生节奏断点,防止从 RED 滑入 GREEN 再滑入下一个行为点
50
+ - **GREEN**:写最简单的代码通过测试
51
+ - 不添加功能、不重构其他代码、不"改进"超出测试范围的内容
52
+ - ⛔ **执行 GREEN Scope 声明**(见 `opsx-tdd-rules/rules/green-scope-declaration.md`):
53
+ 1. 列出当前 RED 测试的断言清单
54
+ 2. 列出 design.md 中本 DES 元素的完整流程步骤
55
+ 3. 标记步骤归属(✅ 属于当前 RED / ⛔ 属于后续 RED)
56
+ 4. 仅实现标记为 ✅ 的步骤
57
+ - ⛔ **逐条确认 YAGNI 围栏**:读取 tasks.md 中本 GREEN 任务的 YAGNI 围栏声明,逐条确认"未实现 [后续 RED 的行为]:✅"
58
+ - **Verify GREEN**(强制执行):
59
+ - 确认测试通过
60
+ - 其他测试仍通过
61
+ - 输出纯净(无错误/警告)
62
+ - 测试失败?修复代码,不是修复测试
63
+ - **GREEN Scope 门禁**(强制执行,在 Verify GREEN 之后):
64
+ - 检查生产代码中是否有未被当前 RED 断言覆盖的逻辑分支
65
+ - 若存在且属于后续 RED 的行为 → 删除多余代码
66
+ - 自检:"当前实现是否只覆盖了当前 RED 的断言?"
67
+ - 若发现越界 → 删除越界代码,重新运行测试确认仍绿
68
+ - **REFACTOR**:仅在绿色之后
69
+ - 移除重复、改善命名、提取辅助函数
70
+ - 保持测试绿色,不添加行为
71
+ - ⛔ 执行 `opsx-tdd-rules/rules/refactor-checklist.md`(7 项重构检查点)
72
+ - **Repeat**:下一个失败测试,下一个功能
73
+
74
+ ## §4 执行门禁
75
+
76
+ > 完整规则见 `opsx-tdd-rules/rules/test-execution-gate.md`,此处仅保留快速参考。
77
+
78
+ | test-strategy | 行为 |
79
+ |---------------|------|
80
+ | `tdd` | ⛔ 强制执行:RED 确认失败、GREEN 确认通过、REFACTOR 全部测试仍绿 |
81
+ | `impl-first` | ⚠️ 警告模式:运行测试,失败时显示警告但允许继续 |
82
+ | `none` | 跳过:不执行测试门禁 |
83
+
84
+ ## §5 TDD 策略定义
85
+
86
+ > 完整规则见 `opsx-tdd-rules/rules/tdd-strategy-selection.md`,此处仅保留快速参考。
87
+
88
+ 三种策略(tdd/impl-first/none)的定义与适用场景:
89
+
90
+ - **A) TDD(红绿重构循环)**:每个行为点先写失败测试(红),再写最少代码让它通过(绿),最后重构。DAG: RED → GREEN → REFACTOR → ...。任务数量约为模块级拆分的 3-5 倍。适合核心业务逻辑/质量要求高/需要测试驱动设计。
91
+ - **B) Impl-First(代码先行)**:先生成实现任务,测试作为验证步骤。DAG: 实现代码 → 测试验证。适合 UI 层/配置类/快速原型。
92
+ - **C) None(仅实现)**:不生成测试任务,仅编译检查。适合简单配置/文档更新。
93
+
94
+ ## §6 Controller 层策略
95
+
96
+ > 完整规则见 `opsx-tdd-rules/rules/controller-strategy.md`,此处仅保留快速参考。
97
+
98
+ | 策略 | 说明 | 适用 |
99
+ |------|------|------|
100
+ | 策略 A | 为每个 Controller 接口生成 RED 测试(@WebMvcTest),拆为 RED→GREEN 对 | Controller 含业务逻辑 |
101
+ | 策略 B | Controller 作为非 TDD 模块,独立接口层任务,仅做编译检查 | Controller 为纯接线(调用 Service + 返回 Result) |
102
+
103
+ 必须在 tasks.md §2.0 中声明使用哪种策略。
104
+
105
+ ## §7 合理化预防表
106
+
107
+ | 借口 | 现实 |
108
+ |------|------|
109
+ | "太简单不需要测试" | 简单代码也会出错。测试只需30秒。 |
110
+ | "我之后测试" | 立即通过的测试什么也证明不了。 |
111
+ | "后写测试能达到同样目标" | 后写测试="这做什么?" 先写测试="这应该做什么?" |
112
+ | "已经手动测试了" | 临时测试 ≠ 系统测试。无记录,无法重跑。 |
113
+ | "删除X小时是浪费" | 沉没成本谬误。保留未验证代码是技术债务。 |
114
+ | "保留作为参考,先写测试" | 你会改编它。那就是后写测试。删除就是删除。 |
115
+ | "需要先探索" | 可以。但扔掉探索代码,用TDD重新开始。 |
116
+ | "测试困难=设计不清晰" | 听测试的。难测试=难使用。 |
117
+ | "TDD会拖慢我" | TDD比调试快。务实=先测试。 |
118
+ | "手动测试更快" | 手动测试无法证明边界情况。每次改动都要重测。 |
119
+ | "现有代码没有测试" | 你在改进它。为现有代码添加测试。 |
120
+ | "这次不同因为..." | 不,没有不同。 |
121
+
122
+ ## §8 红旗列表
123
+
124
+ 以下信号出现时,**STOP and Start Over**:
125
+
126
+ - 代码先于测试
127
+ - 实现后写测试
128
+ - 测试立即通过
129
+ - 无法解释测试为何失败
130
+ - 测试"稍后"添加
131
+ - 合理化"就这一次"
132
+ - "我已经手动测试过了"
133
+ - "后写测试能达到同样目的"
134
+ - "这是精神而非仪式"
135
+ - "保留作为参考"或"改编现有代码"
136
+ - "已经花了X小时,删除是浪费"
137
+
138
+ > 所有这些都意味着:删除代码,用 TDD 重新开始。
139
+
140
+ ## §9 完成验证清单
141
+
142
+ 标记工作完成前必须全部勾选:
143
+
144
+ - [ ] 每个新函数/方法都有测试
145
+ - [ ] 在实现前观看了每个测试失败
146
+ - [ ] 每个测试因预期原因失败(功能缺失,非拼写错误)
147
+ - [ ] 写了最小代码通过每个测试
148
+ - [ ] 所有测试通过
149
+ - [ ] 输出纯净(无错误/警告)
150
+ - [ ] 测试使用真实代码(仅在不可避免时使用 mock)
151
+ - [ ] 边界情况和错误已覆盖
152
+
153
+ > Can't check all boxes? You skipped TDD. Start over.
154
+
155
+ ## §10 跨技能引用
156
+
157
+ - → `opsx-tdd-quality`:单测代码质量标准(Mock 边界矩阵、命名规范、Java 规则等)
158
+ - → `opsx-tdd-anti-patterns`:测试反模式检测(15 种反模式 + 门禁函数)
159
+ - → `opsx-tdd-review`:测试审查(8 项质量检查 + 缺失测试检测)
160
+ - → `opsx-tdd-metrics`:度量分析(隔离评分、命名评分、覆盖率缺口)
161
+ - → `opsx-tdd-rules`:规则库(DAG 规则、Controller 策略、telemetry 模板等)
162
+ - `rules/green-yagni-fence.md`:GREEN 任务 YAGNI 围栏(引用方:opsx-task)
163
+ - `rules/green-scope-declaration.md`:GREEN Scope 声明(引用方:opsx-apply)
164
+ - `rules/des-step-annotation.md`:DES 步骤级标注(引用方:opsx-design)
165
+ - `rules/multi-validation-split.md`:多校验拆分(引用方:opsx-spec)
166
+ - `rules/exception-path-coverage.md`:异常路径测试覆盖门禁(引用方:opsx-task, opsx-apply, opsx-check)
167
+ - `rules/refactor-checklist.md`:REFACTOR 阶段检查点(引用方:opsx-apply, opsx-tdd-core)
@@ -0,0 +1,55 @@
1
+ ---
2
+ description: "opsx-tdd-core 自检清单 — TDD 执行合规自检、合规性检查、完成验证。仅在执行 TDD 任务自检时读取。"
3
+ ---
4
+
5
+ # opsx-tdd-core — 自检清单
6
+
7
+ > 仅在执行 TDD 任务自检时读取。日常流程见 `SKILL.md`。
8
+
9
+ ---
10
+
11
+ ## §A TDD 执行合规自检(11 项)
12
+
13
+ ⛔ 每完成一个 RED/GREEN/REFACTOR 任务后,必须逐项勾选:
14
+
15
+ - [ ] RED 任务已运行测试并确认失败
16
+ - [ ] RED 失败原因是"功能未实现"而非编译错误
17
+ - [ ] ⛔ **RED 只写了当前行为点的测试**:测试文件中未提前编写后续 RED 的测试方法
18
+ - [ ] ⛔ **RED→GREEN 中断声明已执行**:RED 确认失败后,显式声明了"🔴 RED-N 确认失败,现在进入 GREEN-N"
19
+ - [ ] GREEN 任务已运行测试确认通过
20
+ - [ ] GREEN 未提前实现没有测试要求的功能
21
+ - [ ] ⛔ **GREEN Scope 越界检测**:GREEN 实现后检查生产代码是否包含未被当前 RED 断言覆盖的逻辑分支(规则见 `opsx-tdd-rules/rules/green-scope-declaration.md` §Scope 自检)
22
+ - [ ] ⛔ **GREEN YAGNI 围栏逐条确认**:读取 tasks.md 中本 GREEN 任务的 YAGNI 围栏声明,逐条确认"未实现 [后续 RED 的行为]:✅"
23
+ - [ ] ⛔ **GREEN Scope 门禁已执行**:Verify GREEN 之后,检查生产代码无越界逻辑分支
24
+ - [ ] REFACTOR 后全部测试仍绿
25
+ - [ ] 未出现"先写生产代码再补测试"的情况
26
+
27
+ ## §B TDD 合规性检查(10 项)
28
+
29
+ 仅 `test-strategy=tdd` 时执行:
30
+
31
+ - [ ] RED 任务验收标准包含"测试运行失败"
32
+ - [ ] 无"断言为空"或"编译通过但断言为空"的验收标准
33
+ - [ ] GREEN 任务为行为级粒度(一对一对应 RED)
34
+ - [ ] DAG 存在 RED→GREEN 循环对
35
+ - [ ] 非 TDD 模块未拆红绿循环
36
+ - [ ] GREEN 任务验收标准为"让对应 RED 通过"(而非"实现完整功能")
37
+ - [ ] GREEN 任务输出不含未测试的 Controller/Filter/Config
38
+ - [ ] 已声明 Controller 层处理策略(策略 A 或 B)
39
+ - [ ] 每个 RED 任务包含测试方法名(`{method}_{state}_{outcome}` 格式)
40
+ - [ ] 每个 REFACTOR 任务列出至少 2 个具体重构点
41
+
42
+ ## §C 完成验证清单(8 项)
43
+
44
+ 标记工作完成前必须全部勾选:
45
+
46
+ - [ ] 每个新函数/方法都有测试
47
+ - [ ] 在实现前观看了每个测试失败
48
+ - [ ] 每个测试因预期原因失败(功能缺失,非拼写错误)
49
+ - [ ] 写了最小代码通过每个测试
50
+ - [ ] 所有测试通过
51
+ - [ ] 输出纯净(无错误/警告)
52
+ - [ ] 测试使用真实代码(仅在不可避免时使用 mock)
53
+ - [ ] 边界情况和错误已覆盖
54
+
55
+ > Can't check all boxes? You skipped TDD. Start over.