@xulthekl/team-flow 0.33.0 → 0.34.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 +1 -1
- 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 -0
- package/CHANGELOG.md +35 -0
- package/CONTRIBUTING.md +44 -0
- package/GEMINI.md +1 -1
- package/INSTALL.md +1 -1
- package/README.md +1 -1
- package/docs/README_en.md +1 -1
- package/docs/solutions/INDEX.md +1 -0
- package/docs/solutions/cross-phase/2026-08-04-no-summary.md +17 -0
- 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 +1 -1
- package/scripts/lib/conventions-generator.mjs +350 -0
- package/scripts/lib/test-record.mjs +65 -2
- package/skills/test-strategy/SKILL.md +37 -0
- package/skills/test-strategy/references/integration-test-contracts.md +237 -0
- package/skills/test-strategy/references/integration-test-isolation.md +346 -0
- package/skills/test-strategy/references/test-quality-rules.md +292 -0
- package/skills/workflow-bootstrap/SKILL.md +40 -3
- package/templates/agent-template.md +41 -0
- package/templates/conventions/_manifest.json +39 -0
- package/templates/conventions/glaf4-compliant/java-testing.md +367 -0
- package/templates/conventions/glaf4-compliant/spring-patterns.md +415 -0
- package/templates/conventions/js-testing.md +261 -0
- package/templates/conventions/python-testing.md +333 -0
|
@@ -93,6 +93,55 @@ const PARSERS = {
|
|
|
93
93
|
pytest: parsePytest,
|
|
94
94
|
};
|
|
95
95
|
|
|
96
|
+
// ── Failure Analysis 分类法(v0.13 §57,来自 glaf4-test analyze-surefire-failures.py)────────
|
|
97
|
+
|
|
98
|
+
/** 测试失败分类:assertion_failure / runtime_error / framework_error / compile_error / dependency_blocker / unknown */
|
|
99
|
+
export function classifyFailure(text) {
|
|
100
|
+
const lower = text.toLowerCase();
|
|
101
|
+
|
|
102
|
+
// 1. 编译错误
|
|
103
|
+
if (lower.includes('compilation error') || lower.includes('cannot find symbol') ||
|
|
104
|
+
lower.includes('incompatible types') || lower.includes('method does not override') ||
|
|
105
|
+
lower.includes('syntaxerror') || lower.includes('indentationerror')) {
|
|
106
|
+
return 'compile_error';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 2. 依赖阻塞
|
|
110
|
+
if (lower.includes('connection refused') || lower.includes('connection timed out') ||
|
|
111
|
+
lower.includes('unknownhostexception') || lower.includes('could not resolve host') ||
|
|
112
|
+
lower.includes('no such file or directory') || lower.includes('module not found') ||
|
|
113
|
+
lower.includes('package does not exist') || lower.includes('dependency') && lower.includes('failed')) {
|
|
114
|
+
return 'dependency_blocker';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// 3. 框架错误
|
|
118
|
+
if (lower.includes('applicationcontextexception') || lower.includes('beandefinitionstoreexception') ||
|
|
119
|
+
lower.includes('nosuchbeandefinitionexception') || lower.includes('unsatisfieddependencyexception') ||
|
|
120
|
+
lower.includes('spring') && lower.includes('failed to load') ||
|
|
121
|
+
lower.includes('contextconfiguration') || lower.includes('testcontext')) {
|
|
122
|
+
return 'framework_error';
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 4. 运行时异常
|
|
126
|
+
if (lower.includes('nullpointerexception') || lower.includes('illegalargumentexception') ||
|
|
127
|
+
lower.includes('indexoutofboundsexception') || lower.includes('classcastexception') ||
|
|
128
|
+
lower.includes('numberformatexception') || lower.includes('stackoverflowerror') ||
|
|
129
|
+
lower.includes('outofmemoryerror') || lower.includes('runtimeerror') ||
|
|
130
|
+
lower.includes('typeerror') || lower.includes('referenceerror')) {
|
|
131
|
+
return 'runtime_error';
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// 5. 断言失败
|
|
135
|
+
if (lower.includes('assertionerror') || lower.includes('expected') && lower.includes('but was') ||
|
|
136
|
+
lower.includes('assertionfailederror') || lower.includes('expected :') && lower.includes('actual :') ||
|
|
137
|
+
lower.includes('expect(') || lower.includes('assert') && lower.includes('failed')) {
|
|
138
|
+
return 'assertion_failure';
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// 6. 未知
|
|
142
|
+
return 'unknown';
|
|
143
|
+
}
|
|
144
|
+
|
|
96
145
|
/** auto 识别:按内容特征匹配 runner。 */
|
|
97
146
|
export function detectRunner(text) {
|
|
98
147
|
const trimmed = text.trim();
|
|
@@ -180,7 +229,18 @@ export async function run(args) {
|
|
|
180
229
|
// 判定:failed==0 且 total>0 才算 pass(total=0 空真拒绝,v0.13 §50.2)
|
|
181
230
|
const verdict = stats.failed === 0 && stats.total > 0 ? 'pass' : 'fail';
|
|
182
231
|
const ts = new Date().toISOString();
|
|
183
|
-
|
|
232
|
+
|
|
233
|
+
// Failure Analysis 分类(v0.13 §57,来自 glaf4-test)
|
|
234
|
+
let failureClass = null;
|
|
235
|
+
if (verdict === 'fail') {
|
|
236
|
+
const rawText = fromStat.isFile()
|
|
237
|
+
? readFileSync(fromPath, 'utf-8')
|
|
238
|
+
: '';
|
|
239
|
+
failureClass = classifyFailure(rawText);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const failureInfo = failureClass ? ` failure_class=${failureClass}` : '';
|
|
243
|
+
const record = `${verdict}: total=${stats.total} passed=${stats.passed} failed=${stats.failed} skipped=${stats.skipped} runner=${runner} recorded-by=tf-test-record ts=${ts}${failureInfo}`;
|
|
184
244
|
|
|
185
245
|
// 原始证据落盘(tests-passing 门禁与 doctor 巡检都要求该文件存在)
|
|
186
246
|
const evidenceDir = join(changeDir, '.superpowers', 'test-evidence');
|
|
@@ -200,11 +260,14 @@ export async function run(args) {
|
|
|
200
260
|
writeState(changeDir, state);
|
|
201
261
|
|
|
202
262
|
if (values.json) {
|
|
203
|
-
|
|
263
|
+
const jsonResult = { ok: true, verdict, ...stats, runner, test_result: record, test_evidence_path: evidenceRel };
|
|
264
|
+
if (failureClass) jsonResult.failure_class = failureClass;
|
|
265
|
+
console.log(JSON.stringify(jsonResult));
|
|
204
266
|
} else {
|
|
205
267
|
console.log(`${verdict === 'pass' ? '✅' : '❌'} test_result recorded (${runner}): total=${stats.total} passed=${stats.passed} failed=${stats.failed} skipped=${stats.skipped}`);
|
|
206
268
|
console.log(` evidence: ${evidenceRel}`);
|
|
207
269
|
if (verdict === 'fail') {
|
|
270
|
+
console.log(` failure_class: ${failureClass}`);
|
|
208
271
|
console.log(' closing 将被 tests-passing 门禁阻断:修复失败后重新运行测试套件并再次 tf test record。');
|
|
209
272
|
}
|
|
210
273
|
}
|
|
@@ -68,3 +68,40 @@ user-invocable: false
|
|
|
68
68
|
| **TDD** | 新功能/新行为 | RED→GREEN→REFACTOR |
|
|
69
69
|
| **CHARACTERIZATION** | 遗留代码行为捕获 | 只写不改(不改生产代码) |
|
|
70
70
|
| **REGRESSION** | 缺陷复现+修复 | 先复现再修 |
|
|
71
|
+
|
|
72
|
+
## 8. 组合覆盖声明
|
|
73
|
+
|
|
74
|
+
> 来源:glaf4-test design-worker 的 combination_coverage 机制(v0.13 §55)
|
|
75
|
+
|
|
76
|
+
当目标方法满足以下条件之一时,矩阵中**必须声明**组合覆盖策略:
|
|
77
|
+
|
|
78
|
+
### 触发条件
|
|
79
|
+
|
|
80
|
+
1. **多参数方法**(param_count > 1):声明 `pairwise`,要求至少一个 equivalence/boundary 用例覆盖参数组合
|
|
81
|
+
2. **有分支逻辑**(if/case/switch):声明 `branch`,要求至少一个 state/path 用例覆盖各分支
|
|
82
|
+
|
|
83
|
+
### 声明格式
|
|
84
|
+
|
|
85
|
+
在 test-matrix.md 的 description 列中声明:
|
|
86
|
+
|
|
87
|
+
- `[pairwise] 已覆盖参数组合 A×B, A×C`
|
|
88
|
+
- `[branch] 已覆盖 true/false 分支`
|
|
89
|
+
- `[not_applicable] 单参数无分支,无需组合覆盖`
|
|
90
|
+
|
|
91
|
+
### 对账规则
|
|
92
|
+
|
|
93
|
+
contract-builder 生成矩阵后,必须校验:
|
|
94
|
+
- 声明 `pairwise` 的目标,必须有至少 1 个 equivalence 或 boundary 用例覆盖参数组合
|
|
95
|
+
- 声明 `branch` 的目标,必须有至少 1 个 state 或 path 用例覆盖各分支
|
|
96
|
+
- 声明 `not_applicable` 的目标,必须提供理由(如"单参数无分支")
|
|
97
|
+
|
|
98
|
+
### 示例
|
|
99
|
+
|
|
100
|
+
```markdown
|
|
101
|
+
| ID | work_mode | test_tier | design_method | description | priority |
|
|
102
|
+
|----|-----------|-----------|---------------|-------------|----------|
|
|
103
|
+
| TC-001 | TDD | unit | equivalence | [pairwise] 正常查询:page=1, size=10 | P0 |
|
|
104
|
+
| TC-002 | TDD | unit | boundary | [pairwise] 边界:page=0, size=10 | P1 |
|
|
105
|
+
| TC-003 | TDD | unit | boundary | [pairwise] 边界:page=1, size=0 | P1 |
|
|
106
|
+
| TC-004 | TDD | unit | error | [not_applicable] 单参数无分支,无需组合覆盖 | P1 |
|
|
107
|
+
```
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# Integration Test Contracts(集成测试契约)
|
|
2
|
+
|
|
3
|
+
> 来源:glaf4-test social-test-contracts.md 的通用模式(v0.13 §58)
|
|
4
|
+
> 用途:集成测试的组织方法论,contract-builder 生成矩阵时参考
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 一、核心概念
|
|
9
|
+
|
|
10
|
+
**社交测试(Social Test)**:跨类/跨层交互的测试,需要声明式契约来明确测试边界和依赖。
|
|
11
|
+
|
|
12
|
+
**契约的作用**:
|
|
13
|
+
- 明确测试的输入和输出
|
|
14
|
+
- 声明依赖的真实/mock/stub
|
|
15
|
+
- 定义测试隔离和清理策略
|
|
16
|
+
- 确保测试可重复和可维护
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 二、五种契约类型
|
|
21
|
+
|
|
22
|
+
### 1. 入口契约(Entry Contract)
|
|
23
|
+
|
|
24
|
+
**定义**:系统边界入口声明
|
|
25
|
+
|
|
26
|
+
**内容**:
|
|
27
|
+
- API 端点(URL、HTTP 方法、请求格式)
|
|
28
|
+
- 消息队列(exchange、routingKey、消息格式)
|
|
29
|
+
- 定时任务(cron 表达式、触发条件)
|
|
30
|
+
|
|
31
|
+
**示例**:
|
|
32
|
+
```markdown
|
|
33
|
+
## 入口契约
|
|
34
|
+
|
|
35
|
+
- API: `POST /api/users`
|
|
36
|
+
- Content-Type: application/json
|
|
37
|
+
- 请求体: `{ "name": "string", "email": "string" }`
|
|
38
|
+
- 认证: Bearer Token
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 2. 协作者契约(Collaborator Contract)
|
|
42
|
+
|
|
43
|
+
**定义**:依赖分级声明
|
|
44
|
+
|
|
45
|
+
**分级**:
|
|
46
|
+
| 级别 | 说明 | 使用场景 |
|
|
47
|
+
|------|------|---------|
|
|
48
|
+
| **真实(Real)** | 使用真实实现 | Repository 层、内部 Service |
|
|
49
|
+
| **Mock** | 使用 mock 框架创建 | 外部 API、第三方服务 |
|
|
50
|
+
| **Stub** | 使用固定返回值 | 简单依赖、配置服务 |
|
|
51
|
+
|
|
52
|
+
**示例**:
|
|
53
|
+
```markdown
|
|
54
|
+
## 协作者契约
|
|
55
|
+
|
|
56
|
+
| 协作者 | 级别 | 理由 |
|
|
57
|
+
|--------|------|------|
|
|
58
|
+
| UserRepository | Real | 测试真实持久化逻辑 |
|
|
59
|
+
| EmailService | Mock | 外部服务,避免真实发送 |
|
|
60
|
+
| ConfigService | Stub | 返回固定配置值 |
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 3. 数据契约(Data Contract)
|
|
64
|
+
|
|
65
|
+
**定义**:测试数据规格声明
|
|
66
|
+
|
|
67
|
+
**内容**:
|
|
68
|
+
- 输入数据格式和约束
|
|
69
|
+
- 输出数据格式和验证点
|
|
70
|
+
- 测试数据准备方式
|
|
71
|
+
|
|
72
|
+
**示例**:
|
|
73
|
+
```markdown
|
|
74
|
+
## 数据契约
|
|
75
|
+
|
|
76
|
+
### 输入
|
|
77
|
+
- name: string, 1-50 字符
|
|
78
|
+
- email: string, 有效邮箱格式
|
|
79
|
+
|
|
80
|
+
### 输出
|
|
81
|
+
- User 对象,包含 id、name、email、createdAt
|
|
82
|
+
- id: 雪花算法生成,非空
|
|
83
|
+
- createdAt: 当前时间,非空
|
|
84
|
+
|
|
85
|
+
### 准备方式
|
|
86
|
+
- 使用 Builder 模式构建测试数据
|
|
87
|
+
- 每个测试独立数据,避免共享状态
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 4. 中间件契约(Middleware Contract)
|
|
91
|
+
|
|
92
|
+
**定义**:基础设施交互规格
|
|
93
|
+
|
|
94
|
+
**内容**:
|
|
95
|
+
| 中间件 | 交互方式 | 测试策略 |
|
|
96
|
+
|--------|---------|---------|
|
|
97
|
+
| **数据库** | SQL 查询/写入 | H2 内存库 / @Transactional 回滚 |
|
|
98
|
+
| **消息队列** | 发送/接收消息 | rabbitmq-mock / embedded broker |
|
|
99
|
+
| **缓存** | 读写 Redis | embedded-redis / mock |
|
|
100
|
+
| **外部 HTTP** | 调用第三方 API | MockWebServer / WireMock |
|
|
101
|
+
|
|
102
|
+
**示例**:
|
|
103
|
+
```markdown
|
|
104
|
+
## 中间件契约
|
|
105
|
+
|
|
106
|
+
| 中间件 | 交互 | 测试策略 |
|
|
107
|
+
|--------|------|---------|
|
|
108
|
+
| MySQL | INSERT/SELECT | H2 内存库,@Transactional 回滚 |
|
|
109
|
+
| RabbitMQ | 发送用户创建事件 | rabbitmq-mock |
|
|
110
|
+
| Redis | 缓存用户信息 | embedded-redis (port 6378) |
|
|
111
|
+
| 支付网关 | 调用支付 API | MockWebServer |
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 5. 清理契约(Cleanup Contract)
|
|
115
|
+
|
|
116
|
+
**定义**:测试隔离清理声明
|
|
117
|
+
|
|
118
|
+
**原则**:
|
|
119
|
+
- 每个测试独立,不共享状态
|
|
120
|
+
- 测试后清理所有创建的数据
|
|
121
|
+
- 异步操作需要等待完成
|
|
122
|
+
|
|
123
|
+
**策略**:
|
|
124
|
+
| 场景 | 清理方式 |
|
|
125
|
+
|------|---------|
|
|
126
|
+
| **同步操作** | @Transactional 自动回滚 |
|
|
127
|
+
| **异步操作** | 手动清理(@AfterEach) |
|
|
128
|
+
| **消息队列** | 清空队列 |
|
|
129
|
+
| **缓存** | 清空 key |
|
|
130
|
+
|
|
131
|
+
**示例**:
|
|
132
|
+
```markdown
|
|
133
|
+
## 清理契约
|
|
134
|
+
|
|
135
|
+
- 数据库:@Transactional 自动回滚
|
|
136
|
+
- 消息队列:@AfterEach 清空队列
|
|
137
|
+
- 缓存:@AfterEach 清空测试 key
|
|
138
|
+
- ThreadLocal:@AfterEach 清理 TraceIdHolder
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## 三、契约声明格式
|
|
144
|
+
|
|
145
|
+
在 test-matrix.md 的集成测试 case 中,使用以下格式声明契约:
|
|
146
|
+
|
|
147
|
+
```markdown
|
|
148
|
+
| ID | work_mode | test_tier | design_method | description | priority | mock |
|
|
149
|
+
|----|-----------|-----------|---------------|-------------|----------|------|
|
|
150
|
+
| TC-010 | TDD | integration | equivalence | [contract] 创建用户:POST /api/users | P0 | entry:POST /api/users, collaborator:EmailService=Mock, data:User{name,email}, cleanup:@Transactional |
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**字段说明**:
|
|
154
|
+
- `entry`: 入口契约
|
|
155
|
+
- `collaborator`: 协作者契约(Real/Mock/Stub)
|
|
156
|
+
- `data`: 数据契约
|
|
157
|
+
- `middleware`: 中间件契约
|
|
158
|
+
- `cleanup`: 清理契约
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## 四、矩阵生成指南
|
|
163
|
+
|
|
164
|
+
### contract-builder 生成集成测试矩阵时:
|
|
165
|
+
|
|
166
|
+
1. **识别入口**:从 specs/*.md 中提取 API 端点、消息队列、定时任务
|
|
167
|
+
2. **分析依赖**:从代码中识别所有依赖,按真实/mock/stub 分级
|
|
168
|
+
3. **定义数据**:明确输入输出数据格式
|
|
169
|
+
4. **选择中间件**:识别涉及的基础设施,选择测试策略
|
|
170
|
+
5. **设计清理**:根据操作类型(同步/异步)设计清理策略
|
|
171
|
+
|
|
172
|
+
### 示例:用户注册功能
|
|
173
|
+
|
|
174
|
+
```markdown
|
|
175
|
+
## 集成测试矩阵
|
|
176
|
+
|
|
177
|
+
### TC-010: 创建用户成功
|
|
178
|
+
- 入口:POST /api/users
|
|
179
|
+
- 协作者:UserRepository=Real, EmailService=Mock
|
|
180
|
+
- 数据:{name:"John", email:"john@example.com"}
|
|
181
|
+
- 中间件:MySQL=H2
|
|
182
|
+
- 清理:@Transactional
|
|
183
|
+
|
|
184
|
+
### TC-011: 创建用户失败(邮箱已存在)
|
|
185
|
+
- 入口:POST /api/users
|
|
186
|
+
- 协作者:UserRepository=Real(预先插入重复数据)
|
|
187
|
+
- 数据:{name:"John", email:"existing@example.com"}
|
|
188
|
+
- 中间件:MySQL=H2
|
|
189
|
+
- 清理:@Transactional
|
|
190
|
+
- 预期:409 Conflict
|
|
191
|
+
|
|
192
|
+
### TC-012: 创建用户后发送欢迎邮件
|
|
193
|
+
- 入口:POST /api/users
|
|
194
|
+
- 协作者:UserRepository=Real, EmailService=Mock
|
|
195
|
+
- 数据:{name:"John", email:"john@example.com"}
|
|
196
|
+
- 中间件:MySQL=H2, RabbitMQ=rabbitmq-mock
|
|
197
|
+
- 清理:@Transactional + 清空队列
|
|
198
|
+
- 验证:EmailService.sendWelcomeEmail() 被调用
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## 五、最佳实践
|
|
204
|
+
|
|
205
|
+
### 1. 契约最小化
|
|
206
|
+
- 只声明必要的契约
|
|
207
|
+
- 避免过度 mock(内部依赖尽量用真实实现)
|
|
208
|
+
|
|
209
|
+
### 2. 契约可读性
|
|
210
|
+
- 使用表格格式,清晰易读
|
|
211
|
+
- 提供理由说明(为什么选择 Mock/Stub)
|
|
212
|
+
|
|
213
|
+
### 3. 契约可维护性
|
|
214
|
+
- 契约与测试代码同步更新
|
|
215
|
+
- 定期审查契约的有效性
|
|
216
|
+
|
|
217
|
+
### 4. 契约复用
|
|
218
|
+
- 相似功能的契约可以复用
|
|
219
|
+
- 提取公共契约模板
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## 六、与 test-strategy 的关系
|
|
224
|
+
|
|
225
|
+
集成测试契约是 test-strategy §1(Design Method 选择规则)的补充:
|
|
226
|
+
- **基础级**(equivalence/boundary/error):适用于所有测试
|
|
227
|
+
- **扩展级**(path/state/exception/reject):条件触发
|
|
228
|
+
- **高级**(permission/idempotency/concurrency/contract):场景触发
|
|
229
|
+
- **contract**:跨模块/跨服务接口契约,需要声明集成测试契约
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## 变更记录
|
|
234
|
+
|
|
235
|
+
| 日期 | 版本 | 变更内容 |
|
|
236
|
+
|------|------|---------|
|
|
237
|
+
| 2026-08-04 | v1.0 | 从 glaf4-test social-test-contracts.md 抽取通用模式 |
|