@xulthekl/team-flow 0.32.2 → 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 +56 -0
- package/CONTRIBUTING.md +44 -0
- package/GEMINI.md +1 -1
- package/INSTALL.md +1 -1
- package/README.md +1 -1
- package/agents/architecture-design.md +1 -34
- package/agents/architecture-reviewer.md +1 -42
- package/agents/bug-investigator.md +1 -37
- package/agents/build-executor.md +1 -22
- package/agents/change-split-auditor.md +1 -42
- package/agents/code-reviewer.md +1 -42
- package/agents/contract-builder.md +1 -22
- package/agents/cross-change-consistency-checker.md +2 -43
- package/agents/need-explorer.md +1 -22
- package/agents/prd-completeness-reviewer.md +1 -47
- package/agents/prototype-builder.md +1 -41
- package/agents/prototype-env-scout.md +1 -26
- package/agents/prototype-reviewer.md +1 -41
- package/agents/release-archivist.md +1 -22
- package/agents/spec-writer.md +1 -22
- 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 +5 -4
- package/plugin.json +1 -1
- package/scripts/lib/conventions-generator.mjs +350 -0
- package/scripts/lib/test-record.mjs +65 -2
- package/skills/e2e/SKILL.md +1 -1
- package/skills/test-strategy/SKILL.md +38 -1
- 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
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: java-testing
|
|
3
|
+
version: 1.0.0
|
|
4
|
+
updated_at: 2026-08-04
|
|
5
|
+
source: team-flow plugin (glaf4-test compliant)
|
|
6
|
+
description: Java 测试规范(JUnit 5 + Mockito),符合 glaf4-test 要求
|
|
7
|
+
tech_stack: [java, junit5, mockito]
|
|
8
|
+
glaf4_compliant: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Java 测试规范(glaf4-test 兼容)
|
|
12
|
+
|
|
13
|
+
> 本规范符合 glaf4-test 的 Java 测试要求,适用于 JUnit 5 + Mockito 技术栈
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 1. 测试结构
|
|
18
|
+
|
|
19
|
+
### 3-section(基础)
|
|
20
|
+
|
|
21
|
+
```java
|
|
22
|
+
@Test
|
|
23
|
+
void shouldXxx_whenYyy() {
|
|
24
|
+
// Arrange - 准备测试数据
|
|
25
|
+
// Act - 执行被测方法
|
|
26
|
+
// Assert - 验证结果
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 5-section(需要验证过程参数时)
|
|
31
|
+
|
|
32
|
+
```java
|
|
33
|
+
@Test
|
|
34
|
+
void shouldXxx_whenYyy() {
|
|
35
|
+
// Arrange
|
|
36
|
+
// Act
|
|
37
|
+
// Assert
|
|
38
|
+
// Capture - 使用 ArgumentCaptor 捕获参数
|
|
39
|
+
// Assert captured - 验证捕获的参数
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 命名规范
|
|
44
|
+
|
|
45
|
+
- 测试方法:`should[预期结果]_[条件]` 或 `test[方法名]_[场景]`
|
|
46
|
+
- 测试类:`[被测类]Test`(如 `UserServiceTest`)
|
|
47
|
+
- @DisplayName:中文描述,清晰说明测试场景
|
|
48
|
+
|
|
49
|
+
```java
|
|
50
|
+
@DisplayName("UserService.createUser 测试")
|
|
51
|
+
class UserServiceTest {
|
|
52
|
+
|
|
53
|
+
@Test
|
|
54
|
+
@DisplayName("创建用户成功:输入有效数据,返回用户对象")
|
|
55
|
+
void shouldCreateUser_whenInputValid() {
|
|
56
|
+
// ...
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@Test
|
|
60
|
+
@DisplayName("创建用户失败:邮箱已存在,抛出异常")
|
|
61
|
+
void shouldThrowException_whenEmailExists() {
|
|
62
|
+
// ...
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 2. TDD 铁律
|
|
70
|
+
|
|
71
|
+
### RED → GREEN → REFACTOR
|
|
72
|
+
|
|
73
|
+
1. **RED**:写失败测试,运行,看到失败
|
|
74
|
+
2. **GREEN**:写最小实现,运行,看到通过
|
|
75
|
+
3. **REFACTOR**:清理代码,保持绿色
|
|
76
|
+
|
|
77
|
+
### 禁止行为(Red Flags)
|
|
78
|
+
|
|
79
|
+
- ❌ "先写代码后补测试"
|
|
80
|
+
- ❌ "跳过 RED 确认"
|
|
81
|
+
- ❌ "同时写生产代码和测试代码"
|
|
82
|
+
|
|
83
|
+
### TDD 证据链
|
|
84
|
+
|
|
85
|
+
implementer 必须在报告中提供:
|
|
86
|
+
- **RED**:执行的命令 + 失败输出 + 为什么预期失败
|
|
87
|
+
- **GREEN**:执行的命令 + 通过输出
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 3. Mock 规范(Mockito)
|
|
92
|
+
|
|
93
|
+
### 单元测试
|
|
94
|
+
|
|
95
|
+
```java
|
|
96
|
+
@ExtendWith(MockitoExtension.class)
|
|
97
|
+
class UserServiceTest {
|
|
98
|
+
|
|
99
|
+
@Mock
|
|
100
|
+
private UserRepository userRepository;
|
|
101
|
+
|
|
102
|
+
@InjectMocks
|
|
103
|
+
private UserService userService;
|
|
104
|
+
|
|
105
|
+
@Test
|
|
106
|
+
void testGetUser() {
|
|
107
|
+
// Arrange
|
|
108
|
+
when(userRepository.findById(1L)).thenReturn(Optional.of(new User("John")));
|
|
109
|
+
|
|
110
|
+
// Act
|
|
111
|
+
User user = userService.getUser(1L);
|
|
112
|
+
|
|
113
|
+
// Assert
|
|
114
|
+
assertEquals("John", user.getName());
|
|
115
|
+
verify(userRepository).findById(1L);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**规则**:
|
|
121
|
+
- ✅ 使用 `@Mock` + `@InjectMocks`
|
|
122
|
+
- ✅ 只 mock 协作者,不 mock 被测类
|
|
123
|
+
- ✅ 使用 `@ExtendWith(MockitoExtension.class)`
|
|
124
|
+
- ❌ 禁止 `@SpringBootTest`(单元测试不启动容器)
|
|
125
|
+
- ❌ 禁止 `@MockBean`(单元测试不用 Spring)
|
|
126
|
+
|
|
127
|
+
### 集成测试
|
|
128
|
+
|
|
129
|
+
```java
|
|
130
|
+
@WebMvcTest(UserController.class)
|
|
131
|
+
class UserControllerTest {
|
|
132
|
+
|
|
133
|
+
@Autowired
|
|
134
|
+
private MockMvc mockMvc;
|
|
135
|
+
|
|
136
|
+
@MockBean
|
|
137
|
+
private UserService userService;
|
|
138
|
+
|
|
139
|
+
@Test
|
|
140
|
+
void testCreateUser() throws Exception {
|
|
141
|
+
// Arrange
|
|
142
|
+
when(userService.createUser(any())).thenReturn(new User("John"));
|
|
143
|
+
|
|
144
|
+
// Act & Assert
|
|
145
|
+
mockMvc.perform(post("/api/users")
|
|
146
|
+
.contentType(MediaType.APPLICATION_JSON)
|
|
147
|
+
.content("{\"name\":\"John\"}"))
|
|
148
|
+
.andExpect(status().isOk());
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**规则**:
|
|
154
|
+
- ✅ 使用 `@WebMvcTest` / `@SpringBootTest`
|
|
155
|
+
- ✅ 可以使用 `@MockBean` mock 外部依赖
|
|
156
|
+
- ✅ 使用 MockMvc 测试 HTTP 请求
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 4. 断言规范
|
|
161
|
+
|
|
162
|
+
### 必须有有效断言
|
|
163
|
+
|
|
164
|
+
```java
|
|
165
|
+
// ❌ 违规:没有断言
|
|
166
|
+
@Test
|
|
167
|
+
void testGetUser() {
|
|
168
|
+
userService.getUser(1L);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ❌ 违规:只有弱断言
|
|
172
|
+
@Test
|
|
173
|
+
void testGetUser() {
|
|
174
|
+
User user = userService.getUser(1L);
|
|
175
|
+
assertNotNull(user);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ✅ 正确:有有效断言
|
|
179
|
+
@Test
|
|
180
|
+
void testGetUser() {
|
|
181
|
+
User user = userService.getUser(1L);
|
|
182
|
+
assertNotNull(user);
|
|
183
|
+
assertEquals("John", user.getName());
|
|
184
|
+
assertEquals(25, user.getAge());
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### 禁止调试代码
|
|
189
|
+
|
|
190
|
+
```java
|
|
191
|
+
// ❌ 违规
|
|
192
|
+
@Test
|
|
193
|
+
void testGetUser() {
|
|
194
|
+
User user = userService.getUser(1L);
|
|
195
|
+
System.out.println("User: " + user); // 调试代码
|
|
196
|
+
assertNotNull(user);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ✅ 正确
|
|
200
|
+
@Test
|
|
201
|
+
void testGetUser() {
|
|
202
|
+
User user = userService.getUser(1L);
|
|
203
|
+
assertNotNull(user);
|
|
204
|
+
assertEquals("John", user.getName());
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## 5. 测试数据规范
|
|
211
|
+
|
|
212
|
+
### 禁止硬编码样本数据
|
|
213
|
+
|
|
214
|
+
```java
|
|
215
|
+
// ❌ 违规
|
|
216
|
+
@Test
|
|
217
|
+
void testCreateUser() {
|
|
218
|
+
User user = new User("张三", "13800138000", "test@example.com");
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ✅ 正确:使用有意义的测试数据
|
|
222
|
+
@Test
|
|
223
|
+
void testCreateUser() {
|
|
224
|
+
User user = new User("John Doe", "+1-555-0123", "john.doe@company.com");
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// ✅ 正确:使用 Builder 模式
|
|
228
|
+
@Test
|
|
229
|
+
void testCreateUser() {
|
|
230
|
+
User user = UserBuilder.create()
|
|
231
|
+
.withName("John Doe")
|
|
232
|
+
.withPhone("+1-555-0123")
|
|
233
|
+
.withEmail("john.doe@company.com")
|
|
234
|
+
.build();
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### 禁止真实外部 URL
|
|
239
|
+
|
|
240
|
+
```java
|
|
241
|
+
// ❌ 违规
|
|
242
|
+
@Test
|
|
243
|
+
void testCallApi() {
|
|
244
|
+
String url = "https://api.third-party.com/data";
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// ✅ 正确:使用 mock
|
|
248
|
+
@Test
|
|
249
|
+
void testCallApi() {
|
|
250
|
+
MockWebServer server = new MockWebServer();
|
|
251
|
+
server.enqueue(new MockResponse().setBody("{\"data\":\"test\"}"));
|
|
252
|
+
// ...
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## 6. 异常测试规范
|
|
259
|
+
|
|
260
|
+
### 显式捕获和断言异常
|
|
261
|
+
|
|
262
|
+
```java
|
|
263
|
+
// ❌ 违规:throws Exception
|
|
264
|
+
@Test
|
|
265
|
+
void testGetUser() throws Exception {
|
|
266
|
+
userService.getUser(999L);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ✅ 正确:显式捕获和断言
|
|
270
|
+
@Test
|
|
271
|
+
void testGetUser_NotFound() {
|
|
272
|
+
when(userRepository.findById(999L)).thenReturn(Optional.empty());
|
|
273
|
+
|
|
274
|
+
assertThrows(UserNotFoundException.class, () -> {
|
|
275
|
+
userService.getUser(999L);
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// ✅ 正确:使用 assertThrows 验证异常消息
|
|
280
|
+
@Test
|
|
281
|
+
void testGetUser_NotFound() {
|
|
282
|
+
when(userRepository.findById(999L)).thenReturn(Optional.empty());
|
|
283
|
+
|
|
284
|
+
UserNotFoundException exception = assertThrows(UserNotFoundException.class, () -> {
|
|
285
|
+
userService.getUser(999L);
|
|
286
|
+
});
|
|
287
|
+
assertEquals("User not found: 999", exception.getMessage());
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## 7. 组合覆盖声明
|
|
294
|
+
|
|
295
|
+
当目标方法满足以下条件时,矩阵中必须声明组合覆盖策略:
|
|
296
|
+
|
|
297
|
+
### 多参数方法(param_count > 1)
|
|
298
|
+
|
|
299
|
+
声明 `pairwise`,要求至少一个 equivalence/boundary 用例覆盖参数组合
|
|
300
|
+
|
|
301
|
+
```java
|
|
302
|
+
// findByPage(int page, int size) 有两个参数
|
|
303
|
+
// 需要声明 pairwise,覆盖 page×size 组合
|
|
304
|
+
@Test
|
|
305
|
+
void testFindByPage_Normal() { ... } // page=1, size=10
|
|
306
|
+
@Test
|
|
307
|
+
void testFindByPage_PageZero() { ... } // page=0, size=10
|
|
308
|
+
@Test
|
|
309
|
+
void testFindByPage_SizeZero() { ... } // page=1, size=0
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### 有分支逻辑(if/case/switch)
|
|
313
|
+
|
|
314
|
+
声明 `branch`,要求至少一个 state/path 用例覆盖各分支
|
|
315
|
+
|
|
316
|
+
```java
|
|
317
|
+
// if (user.getStatus() == ACTIVE) { ... } else { ... }
|
|
318
|
+
// 需要声明 branch,覆盖 ACTIVE 和非 ACTIVE 分支
|
|
319
|
+
@Test
|
|
320
|
+
void testGetUser_ActiveUser() { ... } // status = ACTIVE
|
|
321
|
+
@Test
|
|
322
|
+
void testGetUser_InactiveUser() { ... } // status = INACTIVE
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## 8. 测试质量规则
|
|
328
|
+
|
|
329
|
+
参见 `references/test-quality-rules.md`,主要包括:
|
|
330
|
+
|
|
331
|
+
1. 断言质量规则(missing-meaningful-assertion、weak-assertion-only、verify-only-without-assertion)
|
|
332
|
+
2. 调试代码残留规则(system-out、print-stack-trace)
|
|
333
|
+
3. 测试状态规则(disabled-test、unfinished-test-todo)
|
|
334
|
+
4. 测试数据规则(hardcoded-sample-like-value、real-external-url)
|
|
335
|
+
5. 测试结构规则(large-test-class、generic-test-class-name)
|
|
336
|
+
6. 矩阵对账规则(case-method-not-found、case-test-file-mismatch)
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## 9. 测试隔离
|
|
341
|
+
|
|
342
|
+
参见 `references/integration-test-isolation.md`,主要包括:
|
|
343
|
+
|
|
344
|
+
- Repository 层:H2 内存库
|
|
345
|
+
- Service 层(同步):@Transactional
|
|
346
|
+
- Service 层(异步):手动清理
|
|
347
|
+
- API 层:MockMvc + @Transactional
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## 10. 集成测试契约
|
|
352
|
+
|
|
353
|
+
参见 `references/integration-test-contracts.md`,主要包括:
|
|
354
|
+
|
|
355
|
+
- 入口契约:API 端点、消息队列、定时任务
|
|
356
|
+
- 协作者契约:真实/mock/stub 分级
|
|
357
|
+
- 数据契约:输入输出数据格式
|
|
358
|
+
- 中间件契约:数据库、消息队列、缓存、外部 HTTP
|
|
359
|
+
- 清理契约:测试隔离清理策略
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## 变更记录
|
|
364
|
+
|
|
365
|
+
| 日期 | 版本 | 变更内容 |
|
|
366
|
+
|------|------|---------|
|
|
367
|
+
| 2026-08-04 | v1.0 | 初始版本,符合 glaf4-test 要求 |
|