@xulthekl/team-flow 0.30.0 → 0.31.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/always/phase-guard.md +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +2 -2
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor-plugin/marketplace.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/.github/plugin/marketplace.json +2 -2
- package/AGENTS.md +2 -1
- package/CHANGELOG.md +38 -0
- package/GEMINI.md +1 -1
- package/INSTALL.md +1 -1
- package/README.md +2 -2
- package/agents/build-executor.md +1 -0
- package/docs/README_en.md +1 -1
- package/gemini-extension.json +1 -1
- package/hooks/session-start +2 -2
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/plugin.json +2 -2
- package/scripts/guard/checks/test-matrix-complete.mjs +67 -0
- package/scripts/guard/guard.mjs +5 -1
- package/scripts/lib/cmd-state.mjs +9 -4
- package/scripts/lib/hash.mjs +11 -0
- package/scripts/lib/state-loader.mjs +12 -1
- package/scripts/lib/test-matrix-export.mjs +231 -0
- package/scripts/lib/test-merge.mjs +540 -0
- package/scripts/team-flow.mjs +6 -0
- package/skills/build-executor/implementer-prompt.md +38 -3
- package/skills/code-reviewer/SKILL.md +28 -1
- package/skills/code-reviewer/code-reviewer-prompt.md +10 -0
- package/skills/contract-builder/SKILL.md +76 -0
- package/skills/release-archivist/SKILL.md +35 -2
- package/skills/spec-writer/SKILL.md +3 -1
- package/skills/test-strategy/SKILL.md +70 -0
- package/skills/test-strategy/references/adversarial-patterns.md +0 -0
- package/skills/test-strategy/references/complexity-grading.md +137 -0
- package/skills/test-strategy/references/design-methods-detail.md +183 -0
- package/skills/workflow-orchestrator/references/s1-path-router.md +4 -0
- package/skills/workflow-start/references/routing-rules.md +17 -0
- package/tests/lib/cmd-install-workbuddy.test.mjs +1 -1
|
@@ -11,6 +11,13 @@ Read before generating: `proposal.md`, `specs/`, `design.md`, `tasks.md`, then l
|
|
|
11
11
|
|
|
12
12
|
**Architecture Design Outputs (v0.9 §26)**: 若 `architecture/` 目录存在,同时读取 `architecture/architecture.md` / `database.md` / `api.md`,作为执行契约的架构约束补充输入——确保 execution-contract.md 的 Implementation Constraints 段包含架构设计的关键约束(聚合边界/CQRS 分流/API 契约/schema 变更)。`architecture/` 不存在时跳过。
|
|
13
13
|
|
|
14
|
+
**Test Ledger Injection (v0.12 §43.5)**: 若 `docs/test-ledger/` 存在,读取:
|
|
15
|
+
1. `docs/test-ledger/INDEX.md` → 获取相关模块的测试覆盖概览(coverage_status)
|
|
16
|
+
2. `docs/test-ledger/baselines/{module}.md` → 获取已有 case,避免重复设计;读取 Deferred Items → 评估本次是否可解决
|
|
17
|
+
3. 将已有 baseline 和 deferred 项作为 test-matrix.md 生成的增量输入
|
|
18
|
+
|
|
19
|
+
`docs/test-ledger/` 不存在时跳过(首次使用或无历史数据)。
|
|
20
|
+
|
|
14
21
|
## Artifact Mapping
|
|
15
22
|
|
|
16
23
|
| Source | Extract |
|
|
@@ -34,6 +41,75 @@ Before finalizing:
|
|
|
34
41
|
|
|
35
42
|
Must make obvious: approved behavior, out-of-scope, constraints, batches, test obligations, review gates, and conditions that force a rewind to planning. Prefer compression over repeating planning details.
|
|
36
43
|
|
|
44
|
+
## Test Matrix Generation (v0.12 §42)
|
|
45
|
+
|
|
46
|
+
`test-matrix.md` 是 `execution-contract.md` 的**附属产物**(不是独立第 6 核心产物),在 contract 的 `## Test Matrix` 段引用。
|
|
47
|
+
|
|
48
|
+
### Generation Protocol
|
|
49
|
+
|
|
50
|
+
1. **输入来源**:specs/(Scenario + Unit/Integration 标签)、tasks.md(batch + file structure)、test-strategy skill(design_method 规则)、test-ledger baselines(增量输入)
|
|
51
|
+
2. **按模块分组**:为每个有业务逻辑的模块(Service/Controller/Repository 等)生成 case 列表
|
|
52
|
+
3. **复杂度分级**:每个模块标注 trivial/medium/complex,作为用例数下限判据(test-strategy §2)
|
|
53
|
+
4. **design_method 覆盖**:每个模块至少 1 个 `{boundary, equivalence}` case + 1 个 `{error, exception, reject}` case(test-strategy §6 schema 强制覆盖)
|
|
54
|
+
5. **对抗验证**:矩阵生成后执行三招回检(test-strategy §4),缺失则追加 adversarial case
|
|
55
|
+
6. **候选覆盖台账**:列出所有被测候选(方法/类),标注 decision(covered/deferred/not_applicable)
|
|
56
|
+
|
|
57
|
+
### 12-Column Format
|
|
58
|
+
|
|
59
|
+
| case_id | behavior | design_method | input | expected | test_kind | test_tier | mock | work_mode | test_file | test_method_name | run_command |
|
|
60
|
+
|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
61
|
+
|
|
62
|
+
字段说明见 test-strategy skill 的 `references/design-methods-detail.md`。`test_tier` 从 `test_kind` 派生(unit/integration)。
|
|
63
|
+
|
|
64
|
+
### Structure
|
|
65
|
+
|
|
66
|
+
```markdown
|
|
67
|
+
# Test Matrix — {change-name}
|
|
68
|
+
|
|
69
|
+
## Summary
|
|
70
|
+
- Total cases: {N}
|
|
71
|
+
- Modules covered: {N} (complexity: trivial×{n}, medium×{n}, complex×{n})
|
|
72
|
+
- Unit cases: {N} ({percent}%)
|
|
73
|
+
- Integration cases: {N} ({percent}%)
|
|
74
|
+
- Deferred items: {N}
|
|
75
|
+
- Matrix revision: 1
|
|
76
|
+
|
|
77
|
+
## Candidate Coverage Ledger
|
|
78
|
+
| candidate | category | decision | case_ids | reason |
|
|
79
|
+
|
|
80
|
+
## Cases
|
|
81
|
+
### {module-name}
|
|
82
|
+
| case_id | behavior | design_method | input | expected | test_kind | test_tier | mock | work_mode | test_file | test_method_name | run_command |
|
|
83
|
+
|
|
84
|
+
## Adversarial Cases
|
|
85
|
+
| case_id | behavior | design_method | input | expected | test_kind | test_tier | mock | work_mode | test_file | test_method_name | run_command |
|
|
86
|
+
|
|
87
|
+
## Deferred Items
|
|
88
|
+
| case_id | behavior | design_method | reason | deferred_since |
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Post-Generation
|
|
92
|
+
|
|
93
|
+
写入 `test-matrix.md` 后,在 `execution-contract.md` 中添加引用段:
|
|
94
|
+
```markdown
|
|
95
|
+
## Test Matrix
|
|
96
|
+
See `test-matrix.md` for the full test case matrix (附属产物, 独立 hash).
|
|
97
|
+
- Total cases: {N}, Unit: {N}, Integration: {N}, Deferred: {N}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
然后执行 `tf state rebuild <change-dir>` 更新 `test_matrix_hash`。
|
|
101
|
+
|
|
102
|
+
### Hotfix/Tweak Exemption
|
|
103
|
+
|
|
104
|
+
hotfix/tweak workflow 不生成 test-matrix.md(guard 豁免)。设置:
|
|
105
|
+
```bash
|
|
106
|
+
tf state set <change-dir> test_matrix_skipped true
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### GLAF4 Java 路由
|
|
110
|
+
|
|
111
|
+
当项目技术栈为 GLAF4 Java(Spring Boot / JUnit 5 / Mockito)时,提示用户是否调用 `glaf4-test:glaf4-tests` 做精细矩阵设计。用户同意后由 glaf4-tests design stage 生成 `test-matrix.json`,再转换为 team-flow 格式的 `test-matrix.md`。
|
|
112
|
+
|
|
37
113
|
## Approval Model (DP-3)
|
|
38
114
|
|
|
39
115
|
After drafting: summarize handoff rules, identify ambiguity, flag unmapped requirements, ask user to approve explicitly. After approval:
|
|
@@ -34,6 +34,21 @@ Run full test suite. Record total/passed/failed/skipped. Zero failures = PASS.
|
|
|
34
34
|
### Step 2: Completeness
|
|
35
35
|
Compare contract batches against actual diff. Every SHALL/MUST must have implementation evidence. Missing = Critical severity.
|
|
36
36
|
|
|
37
|
+
### Step 2b: Test Matrix Reconciliation (conditional, v0.12 §44.4)
|
|
38
|
+
|
|
39
|
+
If `test-matrix.md` exists:
|
|
40
|
+
1. **Statistics**: total cases / implemented / passed
|
|
41
|
+
2. **Candidate Coverage Ledger audit**: any `decision=deferred` without reasonable reason?
|
|
42
|
+
3. **Complexity tier check**: cases per module meet minimum (trivial≥3 / medium≥5 / complex≥7)?
|
|
43
|
+
4. **Verdict**:
|
|
44
|
+
- Matrix coverage = 100% AND all cases pass → **PASS**
|
|
45
|
+
- Matrix coverage ≥ 90% with reasonable deferred items → **CONDITIONAL (WARN)**
|
|
46
|
+
- Matrix coverage < 90% OR unexplained gaps → **FAIL**
|
|
47
|
+
|
|
48
|
+
If `test-matrix.md` does NOT exist → **SKIP** (legacy change compatibility).
|
|
49
|
+
|
|
50
|
+
Add a report row: `| Test Matrix | PASS/FAIL/WARN/SKIP | [reconciliation summary] |`
|
|
51
|
+
|
|
37
52
|
### Step 3: Coherence
|
|
38
53
|
Compare design decisions against code. Check naming consistency. Inconsistencies = IMPORTANT.
|
|
39
54
|
|
|
@@ -115,7 +130,7 @@ tf arch-merge <change-dir>
|
|
|
115
130
|
|
|
116
131
|
This merges `architecture/{architecture,database,api}.md` and `architecture/sql/` into the global architecture docs. Skip silently when `architecture/` does not exist (architecture-design was `skipped`).
|
|
117
132
|
|
|
118
|
-
**Execution order (mandatory)**: `arch-merge` → `prototype-sync` → `compound promotion`. Do not parallelise — global docs must not be in a half-updated state.
|
|
133
|
+
**Execution order (mandatory, v0.12 §43.4)**: `arch-merge` → `prototype-sync` → `test-merge` → `compound promotion`. Do not parallelise — global docs must not be in a half-updated state.
|
|
119
134
|
|
|
120
135
|
### Prototype Sync (v0.5)
|
|
121
136
|
|
|
@@ -125,12 +140,30 @@ After `arch-merge` completes, run prototype-sync to merge UX deltas back to the
|
|
|
125
140
|
tf prototype-sync <change-dir>
|
|
126
141
|
```
|
|
127
142
|
|
|
128
|
-
**Write-back order (mandatory)**: `arch-merge` → `prototype-sync` → `compound promotion` must be executed **sequentially** within the same change closing. Do not run them in parallel — the global `docs/architecture
|
|
143
|
+
**Write-back order (mandatory, v0.12 §43.4)**: `arch-merge` → `prototype-sync` → `test-merge` → `compound promotion` must be executed **sequentially** within the same change closing. Do not run them in parallel — the global `docs/architecture/`, `prototype/`, and `docs/test-ledger/` must not be in a half-updated state when the next change grounds on them.
|
|
129
144
|
|
|
130
145
|
If `prototype-sync` reports conflicts, list them in the closing summary and flag for manual resolution. Do not block closing on prototype-sync conflicts (advisory level).
|
|
131
146
|
|
|
132
147
|
**Execution verification(v0.24.0)**:`prototype-sync` 命令执行后,检查其 stdout 输出确认合并完成(输出含 `merged`/`no UX delta`/`conflicts` 之一)。若命令未执行或执行失败,Step 5 Report 的 `Prototype sync` 行必须标注 `SKIPPED` 或 `FAILED`,并在 closing summary 中说明原因。**禁止在 prototype-sync 未执行时将 Prototype sync 行标注为已完成**。
|
|
133
148
|
|
|
149
|
+
### Test Merge (v0.12 §43)
|
|
150
|
+
|
|
151
|
+
After `prototype-sync` completes, run test-merge to write test matrix results back to the global test ledger:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
tf test-merge <change-dir>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
This merges `test-matrix.md` into `docs/test-ledger/`:
|
|
158
|
+
- **mergeBaselines**: extract cases by module, incrementally update `baselines/{module}.md`
|
|
159
|
+
- **resolveDeferred**: new cases covering old deferred items → remove from Deferred
|
|
160
|
+
- **appendChangelog**: archive test-matrix.md → `changelog/{change-id}.md`
|
|
161
|
+
- **rewriteIndex**: recalculate module/case/deferred counts, rewrite `INDEX.md`
|
|
162
|
+
|
|
163
|
+
Skip silently when `test-matrix.md` does not exist (legacy change or test_matrix_skipped=true).
|
|
164
|
+
|
|
165
|
+
**Execution verification**: check stdout output for `test-merge complete` confirmation. If the command did not execute or failed, Step 5 Report's `Test Matrix` row (from Step 2b) must note the reason.
|
|
166
|
+
|
|
134
167
|
### Compound Promotion (v0.5)
|
|
135
168
|
|
|
136
169
|
During closing, promote change-level learnings to the global solutions library:
|
|
@@ -88,6 +88,8 @@ Every requirement must be testable. Use SHALL or MUST. Every requirement must ha
|
|
|
88
88
|
|
|
89
89
|
Optional structured AC tags under a Scenario are supported for E2E extraction (v0.4, design spec ch.16): `##### Exception:` (→ EX AC, ×2), `##### State:` (→ ST AC, ×2), `##### Boundary:` (→ BND AC, ×1). These are **OPTIONAL** — omitting them does NOT fail validation. The `e2e` skill applies dimension-conditional gating (absent dimension = N/A, not 0%) plus keyword fallback (error/invalid/fail/边界), so no spec is forced to add tags.
|
|
90
90
|
|
|
91
|
+
Optional test-dimension tags under a Scenario are supported for test-matrix extraction (v0.12 §44.1): `##### Unit:` (→ unit test hints: equivalence classes, boundary values), `##### Integration:` (→ integration test hints: cross-module, transaction boundaries). These are **OPTIONAL** — omitting them does NOT fail validation. The `contract-builder` extracts matrix skeletons from these tags when present, but does not require them.
|
|
92
|
+
|
|
91
93
|
### design.md
|
|
92
94
|
Must have: Context (current state, constraints, stakeholders), Goals, Decisions (Choice + Rationale + Alternatives considered), Risks And Trade-Offs.
|
|
93
95
|
|
|
@@ -127,7 +129,7 @@ Generate one at a time. Confirm each before next. This prevents scope drift —
|
|
|
127
129
|
- `## Why` > 50 chars, `## What Changes`, `## Scope` (In/Out), `## Impact`, `## Capabilities`, no TBD/TODO
|
|
128
130
|
|
|
129
131
|
### specs/
|
|
130
|
-
- SHALL/MUST for required behavior, `#### Scenario:` with WHEN/THEN per requirement, grouped under delta headers, no contradictions; optional `##### Exception:/State:/Boundary:` sub-tags allowed but NOT required (absent dimension = N/A, not 0%). Regression: a spec containing `##### Exception:` must still pass `npm run validate` (validateDeltaSpec must not reject unknown sub-headings).
|
|
132
|
+
- SHALL/MUST for required behavior, `#### Scenario:` with WHEN/THEN per requirement, grouped under delta headers, no contradictions; optional `##### Exception:/State:/Boundary:` sub-tags allowed but NOT required (absent dimension = N/A, not 0%); optional `##### Unit:/Integration:` sub-tags allowed but NOT required (test-matrix hints for contract-builder). Regression: a spec containing `##### Exception:` must still pass `npm run validate` (validateDeltaSpec must not reject unknown sub-headings).
|
|
131
133
|
|
|
132
134
|
### design.md
|
|
133
135
|
- `## Context`, `## Goals`, `## Decisions` (≥1, with Choice+Rationale+Alternatives), `## Risks And Trade-Offs`
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-strategy
|
|
3
|
+
description: 测试设计方法论 skill——design_method 选择、分层策略、对抗验证、复杂度分级。build-executor 通过 skills: 预加载。
|
|
4
|
+
user-invocable: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Test Strategy
|
|
8
|
+
|
|
9
|
+
测试设计方法论的硬规则。build-executor 通过 `skills: [test-strategy]` 预加载。
|
|
10
|
+
详细说明见 `references/design-methods-detail.md`、`references/complexity-grading.md`、`references/adversarial-patterns.md`。
|
|
11
|
+
|
|
12
|
+
## 1. Design Method 选择规则(三级分层)
|
|
13
|
+
|
|
14
|
+
### 基础级(必选——每个被测目标必须覆盖)
|
|
15
|
+
- **equivalence**: 输入域有有效/无效分类
|
|
16
|
+
- **boundary**: 数字/长度/日期/金额/分页存在边界(6 值法:min-1/min/min+1/max-1/max/max+1)
|
|
17
|
+
- **error**: 业务异常、空值、外部依赖失败
|
|
18
|
+
|
|
19
|
+
### 扩展级(条件触发)
|
|
20
|
+
- **path**: 方法存在多分支(圈复杂度 M = 判定节点+1,用例数 ≥ M)
|
|
21
|
+
- **state**: 对象状态改变或业务规则依赖状态迁移
|
|
22
|
+
- **exception**: 显式覆盖异常类型/消息/框架异常映射
|
|
23
|
+
- **reject**: 业务拒绝、准入失败、权限拒绝
|
|
24
|
+
|
|
25
|
+
### 高级(场景触发)
|
|
26
|
+
- **permission**: API 权限、租户、用户上下文
|
|
27
|
+
- **idempotency**: 重复调用、重复消息、补偿逻辑
|
|
28
|
+
- **concurrency**: 锁、事务、异步消息、并发更新
|
|
29
|
+
- **contract**: 跨模块/跨服务接口契约(Feign、MQ 消息格式、领域事件字段)
|
|
30
|
+
|
|
31
|
+
## 2. 复杂度分级用例数
|
|
32
|
+
|
|
33
|
+
| 复杂度 | 判据 | 最少用例 |
|
|
34
|
+
|--------|------|---------|
|
|
35
|
+
| trivial | is_trivial=true(enum/constant/POJO) | ≥3(仅 equivalence + error,boundary 可省) |
|
|
36
|
+
| medium | 默认(无判据命中) | ≥5 |
|
|
37
|
+
| complex | public_methods>15 或 lines>800 或 圈复杂度>10 或 param_count>6 | ≥7 |
|
|
38
|
+
|
|
39
|
+
保守默认:事实是估算非实测 → 强制 medium 档(≥5)。
|
|
40
|
+
|
|
41
|
+
## 3. 分层策略(测试金字塔比例)
|
|
42
|
+
|
|
43
|
+
- unit(test_tier=unit):70-80% 的 case
|
|
44
|
+
- integration(test_tier=integration):≤30% 的 case
|
|
45
|
+
- e2e:由 e2e skill 独立覆盖,不计入本矩阵
|
|
46
|
+
|
|
47
|
+
## 4. 对抗验证三招(矩阵生成后必检)
|
|
48
|
+
|
|
49
|
+
1. **恶意输入**:至少 1 个 case 覆盖 null/空串/超大值/特殊字符
|
|
50
|
+
2. **并发场景**:涉及锁/事务/异步 → 至少 1 个 concurrency case
|
|
51
|
+
3. **依赖失败**:涉及外部依赖 → 至少 1 个 dependency_failure case(超时/熔断/返回空)
|
|
52
|
+
|
|
53
|
+
## 5. 自检门口诀
|
|
54
|
+
|
|
55
|
+
每个方法至少:**1 正常 + 1 边界 + 1 异常 + 1 null/空**
|
|
56
|
+
|
|
57
|
+
## 6. Schema 强制覆盖(test-matrix.md 校验)
|
|
58
|
+
|
|
59
|
+
1. cases 必须包含至少 1 个 `design_method ∈ {boundary, equivalence}` 的 case
|
|
60
|
+
2. cases 必须包含至少 1 个 `design_method ∈ {error, exception, reject}` 的 case
|
|
61
|
+
3. `complexity_tier=trivial` 时降级:允许只覆盖 equivalence + error
|
|
62
|
+
4. 对抗验证段必须存在(恶意输入/并发/依赖失败三类之一,视目标而定)
|
|
63
|
+
|
|
64
|
+
## 7. work_mode 三种模式
|
|
65
|
+
|
|
66
|
+
| work_mode | 适用场景 | TDD 节奏 |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| **TDD** | 新功能/新行为 | RED→GREEN→REFACTOR |
|
|
69
|
+
| **CHARACTERIZATION** | 遗留代码行为捕获 | 只写不改(不改生产代码) |
|
|
70
|
+
| **REGRESSION** | 缺陷复现+修复 | 先复现再修 |
|
|
Binary file
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Complexity Grading
|
|
2
|
+
|
|
3
|
+
复杂度分级的详细规则。SKILL.md §2 的扩展参考。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. 分级标准
|
|
8
|
+
|
|
9
|
+
### trivial(简单)
|
|
10
|
+
|
|
11
|
+
**判据**(命中任一):
|
|
12
|
+
- 纯常量/枚举类(无方法体)
|
|
13
|
+
- POJO/DTO(仅 getter/setter,无业务逻辑)
|
|
14
|
+
- 工具方法的简单委托(`return delegate.doSomething(x)`)
|
|
15
|
+
- 配置文件读取(无校验逻辑)
|
|
16
|
+
|
|
17
|
+
**最少用例数**:≥3
|
|
18
|
+
- equivalence: 1 个正常输入
|
|
19
|
+
- error: 1 个 null/空值
|
|
20
|
+
- boundary: **可省**(trivial 降级特权)
|
|
21
|
+
|
|
22
|
+
**示例**:
|
|
23
|
+
```java
|
|
24
|
+
// ErrorCode.java — 纯枚举
|
|
25
|
+
// OrderDTO.java — 仅 getter/setter
|
|
26
|
+
// StringUtils.isBlank() — 简单委托
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### medium(中等)— 默认
|
|
30
|
+
|
|
31
|
+
**判据**:无 trivial 或 complex 判据命中时,强制 medium。
|
|
32
|
+
|
|
33
|
+
**最少用例数**:≥5
|
|
34
|
+
- equivalence: ≥1 正常 + ≥1 无效
|
|
35
|
+
- boundary: ≥2(至少 1 个下边界 + 1 个上边界)
|
|
36
|
+
- error: ≥1
|
|
37
|
+
|
|
38
|
+
### complex(复杂)
|
|
39
|
+
|
|
40
|
+
**判据**(命中任一):
|
|
41
|
+
- public_methods > 15
|
|
42
|
+
- lines > 800(含注释和空行)
|
|
43
|
+
- 圈复杂度 > 10
|
|
44
|
+
- param_count > 6(单个方法参数超过 6 个)
|
|
45
|
+
- 涉及 ≥3 个外部依赖交互
|
|
46
|
+
- 包含状态机(≥4 个状态)
|
|
47
|
+
|
|
48
|
+
**最少用例数**:≥7
|
|
49
|
+
- equivalence: ≥2 正常 + ≥2 无效
|
|
50
|
+
- boundary: ≥3(至少含 1 个 6 值法完整覆盖)
|
|
51
|
+
- error: ≥1
|
|
52
|
+
- path: ≥1(如果有分支)
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 2. 圈复杂度计算方法
|
|
57
|
+
|
|
58
|
+
### 手动计算
|
|
59
|
+
|
|
60
|
+
从 1 开始(方法本身的 1 条直线执行路径),每遇到以下结构 +1:
|
|
61
|
+
|
|
62
|
+
| 结构 | 增量 |
|
|
63
|
+
|---|---|
|
|
64
|
+
| `if` / `else if` | +1 |
|
|
65
|
+
| `switch` 每个 `case`(含 `default`) | +1 per case |
|
|
66
|
+
| `for` / `while` / `do-while` | +1 |
|
|
67
|
+
| `&&` / `||` 短路运算 | +1 per operator |
|
|
68
|
+
| `catch` | +1 |
|
|
69
|
+
| `?:`(三元表达式) | +1 |
|
|
70
|
+
|
|
71
|
+
**示例**:
|
|
72
|
+
```java
|
|
73
|
+
public void process(Order order) { // 1
|
|
74
|
+
if (order == null) { ... } // +1 = 2
|
|
75
|
+
if (order.getStatus() == PAID // +1 = 3
|
|
76
|
+
&& order.getAmount() > 1000) { ... } // +1 = 4
|
|
77
|
+
for (Item item : order.getItems()) { // +1 = 5
|
|
78
|
+
if (item.isDiscounted()) { ... } // +1 = 6
|
|
79
|
+
switch (item.getType()) {
|
|
80
|
+
case PHYSICAL: ... break; // +1 = 7
|
|
81
|
+
case DIGITAL: ... break; // +1 = 8
|
|
82
|
+
default: ... // +1 = 9
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// 圈复杂度 = 9 → medium 档(未超 10)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 工具辅助
|
|
90
|
+
|
|
91
|
+
| 语言 | 工具 | 命令 |
|
|
92
|
+
|---|---|---|
|
|
93
|
+
| Java | Checkstyle / PMD | `mvn checkstyle:check` / `pmd check` |
|
|
94
|
+
| Java | SonarQube | 自动扫描 |
|
|
95
|
+
| TypeScript | complexity-report | `npx complexity-report src/` |
|
|
96
|
+
| Python | radon | `radon cc src/` |
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 3. 校准规则
|
|
101
|
+
|
|
102
|
+
### 保守默认
|
|
103
|
+
|
|
104
|
+
- 事实是估算非实测 → 不确定时强制 medium 档(≥5)
|
|
105
|
+
- 宁可多做不可漏做 → 边界 case 优先于 happy path
|
|
106
|
+
|
|
107
|
+
### 方法拆分时的处理
|
|
108
|
+
|
|
109
|
+
如果一个方法被拆分为多个小方法:
|
|
110
|
+
- 拆分前:complex(圈复杂度 12)
|
|
111
|
+
- 拆分后:每个子方法 medium(圈复杂度 4-6)
|
|
112
|
+
- **但**:拆分前的 complex 级用例数仍需保留(不因拆分而降级)
|
|
113
|
+
|
|
114
|
+
### 组合方法的计算
|
|
115
|
+
|
|
116
|
+
如果类有多个 public 方法:
|
|
117
|
+
- 每个方法独立计算复杂度
|
|
118
|
+
- 类的总复杂度 = 各方法圈复杂度之和
|
|
119
|
+
- 类的用例数 = 各方法用例数之和(去重共享的 setup/teardown case)
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 4. 与 test-matrix.md 的关联
|
|
124
|
+
|
|
125
|
+
在 test-matrix.md 的 `## Summary` 段中标注每个模块的复杂度分级:
|
|
126
|
+
|
|
127
|
+
```markdown
|
|
128
|
+
## Summary
|
|
129
|
+
- Total cases: 35
|
|
130
|
+
- Modules covered: 4
|
|
131
|
+
- OrderService: complex (圈复杂度 14, ≥7 cases)
|
|
132
|
+
- PaymentValidator: medium (圈复杂度 6, ≥5 cases)
|
|
133
|
+
- ErrorCode: trivial (纯枚举, ≥3 cases)
|
|
134
|
+
- OrderConverter: trivial (POJO 映射, ≥3 cases)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
contract-builder 在生成矩阵时,必须为每个模块标注复杂度分级,作为用例数下限的判据。
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Design Methods Detail
|
|
2
|
+
|
|
3
|
+
10+1 种测试设计方法的详细说明。SKILL.md §1 的扩展参考。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 基础级(必选)
|
|
8
|
+
|
|
9
|
+
### equivalence(等价类划分)
|
|
10
|
+
|
|
11
|
+
**触发条件**:输入域有有效/无效分类。
|
|
12
|
+
|
|
13
|
+
**方法**:
|
|
14
|
+
1. 识别输入参数的有效等价类和无效等价类
|
|
15
|
+
2. 每个等价类取 1 个代表值
|
|
16
|
+
3. 有效类 → 验证正常行为;无效类 → 验证拒绝/异常
|
|
17
|
+
|
|
18
|
+
**示例(Java)**:
|
|
19
|
+
```java
|
|
20
|
+
// 有效等价类:validOrderId (正整数)
|
|
21
|
+
// 无效等价类:null, 0, -1, 超过 MAX_LONG
|
|
22
|
+
@Test void shouldFindOrder_whenValidId() { ... }
|
|
23
|
+
@Test void shouldThrow_whenNullId() { ... }
|
|
24
|
+
@Test void shouldThrow_whenNegativeId() { ... }
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### boundary(边界值分析)
|
|
28
|
+
|
|
29
|
+
**触发条件**:数字/长度/日期/金额/分页存在边界。
|
|
30
|
+
|
|
31
|
+
**6 值法**:对每个边界取 min-1 / min / min+1 / max-1 / max / max+1
|
|
32
|
+
|
|
33
|
+
| 边界类型 | 示例(金额 0.01 ~ 999999.99) |
|
|
34
|
+
|---|---|
|
|
35
|
+
| min-1 | 0.00 → 拒绝 |
|
|
36
|
+
| min | 0.01 → 接受(最小合法) |
|
|
37
|
+
| min+1 | 0.02 → 接受 |
|
|
38
|
+
| max-1 | 999999.98 → 接受 |
|
|
39
|
+
| max | 999999.99 → 接受(最大合法) |
|
|
40
|
+
| max+1 | 1000000.00 → 拒绝 |
|
|
41
|
+
|
|
42
|
+
**日期边界特殊处理**:
|
|
43
|
+
- 闰年:2024-02-29 / 2025-02-28
|
|
44
|
+
- 月末/月初:1月31日 → 2月1日
|
|
45
|
+
- 时区切换:UTC+8 的 23:59 vs UTC 的 15:59
|
|
46
|
+
|
|
47
|
+
### error(错误/异常路径)
|
|
48
|
+
|
|
49
|
+
**触发条件**:业务异常、空值、外部依赖失败。
|
|
50
|
+
|
|
51
|
+
**必须覆盖的三类**:
|
|
52
|
+
1. **参数校验错误**:null、空串、格式错误
|
|
53
|
+
2. **业务规则违反**:库存不足、余额不够、重复操作
|
|
54
|
+
3. **外部依赖失败**:DB 连接超时、HTTP 5xx、MQ 消费失败
|
|
55
|
+
|
|
56
|
+
**示例**:
|
|
57
|
+
```java
|
|
58
|
+
@Test void shouldThrowBizException_whenInsufficientStock() { ... }
|
|
59
|
+
@Test void shouldReturnEmpty_whenDbReturnsNull() { ... }
|
|
60
|
+
@Test void shouldRetry_whenExternalApiTimeout() { ... }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 扩展级(条件触发)
|
|
66
|
+
|
|
67
|
+
### path(路径覆盖)
|
|
68
|
+
|
|
69
|
+
**触发条件**:方法存在多分支。
|
|
70
|
+
|
|
71
|
+
**圈复杂度计算**:M = 判定节点数 + 1
|
|
72
|
+
- `if` → +1
|
|
73
|
+
- `else if` → +1
|
|
74
|
+
- `switch` 每个 `case` → +1
|
|
75
|
+
- `for` / `while` → +1
|
|
76
|
+
- `&&` / `||` 短路运算 → +1
|
|
77
|
+
|
|
78
|
+
**用例数 ≥ M**。示例:M=4(1 个 if + 1 个 switch 3-case)→ ≥4 个 case。
|
|
79
|
+
|
|
80
|
+
### state(状态迁移)
|
|
81
|
+
|
|
82
|
+
**触发条件**:对象状态改变或业务规则依赖状态迁移。
|
|
83
|
+
|
|
84
|
+
**方法**:
|
|
85
|
+
1. 画出状态迁移图(初始态 → 中间态 → 终态)
|
|
86
|
+
2. 每条迁移边至少 1 个 case
|
|
87
|
+
3. 非法迁移(如 CLOSED → PROCESSING)→ 1 个 reject case
|
|
88
|
+
|
|
89
|
+
**示例(订单状态机)**:
|
|
90
|
+
```
|
|
91
|
+
CREATED → PAID → SHIPPED → DELIVERED → CLOSED
|
|
92
|
+
↓ ↑
|
|
93
|
+
CANCELLED ←──────────────┘ (仅 PAID 前可取消)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### exception(异常覆盖)
|
|
97
|
+
|
|
98
|
+
**触发条件**:显式覆盖异常类型/消息/框架异常映射。
|
|
99
|
+
|
|
100
|
+
**必须验证**:
|
|
101
|
+
1. 异常类型是否正确(BusinessException vs SystemException)
|
|
102
|
+
2. 异常消息是否包含上下文(errorCode + 参数值)
|
|
103
|
+
3. 框架异常映射(Spring 的 `@ResponseStatus` → HTTP 状态码)
|
|
104
|
+
|
|
105
|
+
### reject(业务拒绝)
|
|
106
|
+
|
|
107
|
+
**触发条件**:业务拒绝、准入失败、权限拒绝。
|
|
108
|
+
|
|
109
|
+
**与 error 的区别**:error 是"系统出了问题",reject 是"系统正确地拒绝了"。
|
|
110
|
+
|
|
111
|
+
**示例**:
|
|
112
|
+
```java
|
|
113
|
+
@Test void shouldReject_whenOrderAlreadyClosed() { ... }
|
|
114
|
+
@Test void shouldReject_whenUserNotInWhitelist() { ... }
|
|
115
|
+
@Test void shouldReject_whenDuplicateRequest() { ... }
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## 高级(场景触发)
|
|
121
|
+
|
|
122
|
+
### permission(权限控制)
|
|
123
|
+
|
|
124
|
+
**触发条件**:API 权限、租户、用户上下文。
|
|
125
|
+
|
|
126
|
+
**覆盖维度**:
|
|
127
|
+
1. 角色权限:ADMIN / USER / GUEST / ANONYMOUS
|
|
128
|
+
2. 租户隔离:租户 A 不能访问租户 B 的数据
|
|
129
|
+
3. 数据权限:只能操作自己创建的资源
|
|
130
|
+
|
|
131
|
+
### idempotency(幂等性)
|
|
132
|
+
|
|
133
|
+
**触发条件**:重复调用、重复消息、补偿逻辑。
|
|
134
|
+
|
|
135
|
+
**验证模式**:
|
|
136
|
+
1. 调用 N 次 → 效果等同于调用 1 次
|
|
137
|
+
2. MQ 重复消费 → 不重复处理
|
|
138
|
+
3. 补偿操作 → 正向 + 逆向 = 无净效果
|
|
139
|
+
|
|
140
|
+
**示例**:
|
|
141
|
+
```java
|
|
142
|
+
@Test void shouldNotDuplicateOrder_whenRetryCreate() {
|
|
143
|
+
var first = orderService.create(request);
|
|
144
|
+
var second = orderService.create(request);
|
|
145
|
+
assertThat(second.getId()).isEqualTo(first.getId());
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### concurrency(并发安全)
|
|
150
|
+
|
|
151
|
+
**触发条件**:锁、事务、异步消息、并发更新。
|
|
152
|
+
|
|
153
|
+
**验证模式**:
|
|
154
|
+
1. 乐观锁冲突 → 重试或拒绝
|
|
155
|
+
2. 分布式锁 → 同一时刻只有一个执行者
|
|
156
|
+
3. 事务隔离 → 读未提交 / 读已提交 / 可重复读
|
|
157
|
+
4. 异步消息 → 最终一致性
|
|
158
|
+
|
|
159
|
+
### contract(接口契约)
|
|
160
|
+
|
|
161
|
+
**触发条件**:跨模块/跨服务接口契约。
|
|
162
|
+
|
|
163
|
+
**覆盖维度**:
|
|
164
|
+
1. Feign 客户端:请求/响应格式与 provider 一致
|
|
165
|
+
2. MQ 消息:字段名/类型/必填项
|
|
166
|
+
3. 领域事件:事件名/载荷/版本
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 派生字段:test_tier
|
|
171
|
+
|
|
172
|
+
从 `test_kind` 派生 `test_tier`(语言无关的粗粒度分类):
|
|
173
|
+
|
|
174
|
+
| test_kind 值 | test_tier |
|
|
175
|
+
|---|---|
|
|
176
|
+
| pure_unit, mockito_unit, spring_assisted_unit | unit |
|
|
177
|
+
| vitest_unit, vue_test_utils_mount | unit |
|
|
178
|
+
| api_mockmvc_standalone, api_mockmvc_slice, api_mockmvc_boot | integration |
|
|
179
|
+
| service_social, repository_h2 | integration |
|
|
180
|
+
| rabbitmq_social, redis_social | integration |
|
|
181
|
+
| external_api_stub, test_infrastructure | integration |
|
|
182
|
+
|
|
183
|
+
**用途**:test_tier 用于统计和 CI 分级;test_kind 用于路由到正确的编写模板。
|
|
@@ -48,6 +48,10 @@ S1 只做编排动作(需求选择、存在性检查、路径判断、阻塞
|
|
|
48
48
|
|
|
49
49
|
工作流模式复利(L2):S1 路由时额外注入历史 `workflow_pattern` top-3(confidence ≥ 0.5)。详见 state-model.md「工作流模式复利 L2」。
|
|
50
50
|
|
|
51
|
+
## 测试台账注入(v0.12 §43.5,advisory 级)
|
|
52
|
+
|
|
53
|
+
读取 `docs/test-ledger/INDEX.md`(如存在),注入 `coverage_status=partial` 的模块列表。新 change 涉及这些模块时,提示「有未解决的 deferred 测试项,本次可考虑解决」。读取失败时静默跳过,不阻断。
|
|
54
|
+
|
|
51
55
|
## 路由结果显式呈现(强制,B3)
|
|
52
56
|
|
|
53
57
|
路由判断后**必须**向用户确认,路由是建议而非决定:
|
|
@@ -307,3 +307,20 @@ Inference: **hotfix** (≤2 tasks, ≤2 files, no schema/API/new modules), **twe
|
|
|
307
307
|
|
|
308
308
|
## Post-transition
|
|
309
309
|
💡 `tf inject <change-dir>` to update phase-guard artifacts.
|
|
310
|
+
|
|
311
|
+
## Route to glaf4-tests (v0.12 §46, v0.31.0)
|
|
312
|
+
|
|
313
|
+
**触发条件**:`project_type == glaf4-java`(Spring Boot / JUnit 5 / Mockito)AND contract-builder 需要生成 test-matrix。
|
|
314
|
+
|
|
315
|
+
**协议**:
|
|
316
|
+
1. contract-builder 检测项目技术栈(读取 `pom.xml` / `build.gradle` 判断是否 GLAF4 Java)
|
|
317
|
+
2. GLAF4 项目 → 提示用户:「检测到 GLAF4 Java 项目,是否调用 `glaf4-test:glaf4-tests` 做精细测试矩阵设计?」
|
|
318
|
+
3. 用户同意 → 调用 `glaf4-test:glaf4-tests-design` 生成 `test-matrix.json`
|
|
319
|
+
4. `glaf4-tests-validate` 校验矩阵完整性
|
|
320
|
+
5. `scripts/lib/test-matrix-export.mjs` 转换为 team-flow 格式的 `test-matrix.md`
|
|
321
|
+
6. 用户确认(轻量版 DP-A)
|
|
322
|
+
7. 写入 `test-matrix.md`,contract 中添加 `## Test Matrix` 段引用
|
|
323
|
+
|
|
324
|
+
**非 GLAF4 项目**:contract-builder 使用内置 test-strategy skill 直接生成 `test-matrix.md`。
|
|
325
|
+
|
|
326
|
+
**设计决策**:glaf4-tests 对接为**可选增强**,不是必经路径。
|
|
@@ -102,7 +102,7 @@ describe('cmd-install-workbuddy', () => {
|
|
|
102
102
|
process.chdir(tempDir);
|
|
103
103
|
try {
|
|
104
104
|
const plan = planInstall({ homeDir: join(tempDir, 'home') });
|
|
105
|
-
assert.equal(plan.skillNames.length,
|
|
105
|
+
assert.equal(plan.skillNames.length, 24);
|
|
106
106
|
assert.equal(plan.skillsDir, join(plan.pluginRoot, 'skills'));
|
|
107
107
|
assert.ok(existsSync(plan.skillsDir));
|
|
108
108
|
assert.notEqual(plan.skillsDir, join(tempDir, 'skills'));
|