@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.
Files changed (50) hide show
  1. package/.claude/always/phase-guard.md +1 -1
  2. package/.claude-plugin/marketplace.json +1 -1
  3. package/.claude-plugin/plugin.json +1 -1
  4. package/.codex-plugin/plugin.json +1 -1
  5. package/.cursor-plugin/marketplace.json +1 -1
  6. package/.cursor-plugin/plugin.json +1 -1
  7. package/.github/plugin/marketplace.json +2 -2
  8. package/AGENTS.md +2 -0
  9. package/CHANGELOG.md +56 -0
  10. package/CONTRIBUTING.md +44 -0
  11. package/GEMINI.md +1 -1
  12. package/INSTALL.md +1 -1
  13. package/README.md +1 -1
  14. package/agents/architecture-design.md +1 -34
  15. package/agents/architecture-reviewer.md +1 -42
  16. package/agents/bug-investigator.md +1 -37
  17. package/agents/build-executor.md +1 -22
  18. package/agents/change-split-auditor.md +1 -42
  19. package/agents/code-reviewer.md +1 -42
  20. package/agents/contract-builder.md +1 -22
  21. package/agents/cross-change-consistency-checker.md +2 -43
  22. package/agents/need-explorer.md +1 -22
  23. package/agents/prd-completeness-reviewer.md +1 -47
  24. package/agents/prototype-builder.md +1 -41
  25. package/agents/prototype-env-scout.md +1 -26
  26. package/agents/prototype-reviewer.md +1 -41
  27. package/agents/release-archivist.md +1 -22
  28. package/agents/spec-writer.md +1 -22
  29. package/docs/README_en.md +1 -1
  30. package/docs/solutions/INDEX.md +1 -0
  31. package/docs/solutions/cross-phase/2026-08-04-no-summary.md +17 -0
  32. package/gemini-extension.json +1 -1
  33. package/hooks/session-start +2 -2
  34. package/llms.txt +1 -1
  35. package/package.json +5 -4
  36. package/plugin.json +1 -1
  37. package/scripts/lib/conventions-generator.mjs +350 -0
  38. package/scripts/lib/test-record.mjs +65 -2
  39. package/skills/e2e/SKILL.md +1 -1
  40. package/skills/test-strategy/SKILL.md +38 -1
  41. package/skills/test-strategy/references/integration-test-contracts.md +237 -0
  42. package/skills/test-strategy/references/integration-test-isolation.md +346 -0
  43. package/skills/test-strategy/references/test-quality-rules.md +292 -0
  44. package/skills/workflow-bootstrap/SKILL.md +40 -3
  45. package/templates/agent-template.md +41 -0
  46. package/templates/conventions/_manifest.json +39 -0
  47. package/templates/conventions/glaf4-compliant/java-testing.md +367 -0
  48. package/templates/conventions/glaf4-compliant/spring-patterns.md +415 -0
  49. package/templates/conventions/js-testing.md +261 -0
  50. package/templates/conventions/python-testing.md +333 -0
@@ -0,0 +1,415 @@
1
+ ---
2
+ name: spring-patterns
3
+ version: 1.0.0
4
+ updated_at: 2026-08-04
5
+ source: team-flow plugin (glaf4-test compliant)
6
+ description: Spring Boot 测试规范,符合 glaf4-test 要求
7
+ tech_stack: [java, spring-boot]
8
+ glaf4_compliant: true
9
+ ---
10
+
11
+ # Spring Boot 测试规范(glaf4-test 兼容)
12
+
13
+ > 本规范符合 glaf4-test 的 Spring Boot 测试要求
14
+
15
+ ---
16
+
17
+ ## 1. MockMvc 三模式
18
+
19
+ ### standaloneSetup(推荐用于 Controller 单元测试)
20
+
21
+ ```java
22
+ class UserControllerTest {
23
+
24
+ private MockMvc mockMvc;
25
+
26
+ @Mock
27
+ private UserService userService;
28
+
29
+ @BeforeEach
30
+ void setup() {
31
+ mockMvc = MockMvcBuilders.standaloneSetup(new UserController(userService)).build();
32
+ }
33
+
34
+ @Test
35
+ void testGetUser() throws Exception {
36
+ when(userService.getUser(1L)).thenReturn(new User("John"));
37
+
38
+ mockMvc.perform(get("/api/users/1"))
39
+ .andExpect(status().isOk())
40
+ .andExpect(jsonPath("$.name").value("John"));
41
+ }
42
+ }
43
+ ```
44
+
45
+ **适用场景**:
46
+ - 只测试 Controller 层
47
+ - 不加载 Spring 上下文
48
+ - 速度快,隔离性好
49
+
50
+ ### @WebMvcTest(推荐用于 Controller 集成测试)
51
+
52
+ ```java
53
+ @WebMvcTest(UserController.class)
54
+ class UserControllerIntegrationTest {
55
+
56
+ @Autowired
57
+ private MockMvc mockMvc;
58
+
59
+ @MockBean
60
+ private UserService userService;
61
+
62
+ @Test
63
+ void testGetUser() throws Exception {
64
+ when(userService.getUser(1L)).thenReturn(new User("John"));
65
+
66
+ mockMvc.perform(get("/api/users/1"))
67
+ .andExpect(status().isOk())
68
+ .andExpect(jsonPath("$.name").value("John"));
69
+ }
70
+ }
71
+ ```
72
+
73
+ **适用场景**:
74
+ - 测试 Controller + Spring MVC 配置
75
+ - 自动配置 MockMvc
76
+ - 只加载 Web 层
77
+
78
+ ### @SpringBootTest + @AutoConfigureMockMvc(全上下文测试)
79
+
80
+ ```java
81
+ @SpringBootTest
82
+ @AutoConfigureMockMvc
83
+ class UserControllerE2ETest {
84
+
85
+ @Autowired
86
+ private MockMvc mockMvc;
87
+
88
+ @Autowired
89
+ private UserRepository userRepository;
90
+
91
+ @Test
92
+ void testGetUser() throws Exception {
93
+ // Arrange
94
+ User user = userRepository.save(new User("John"));
95
+
96
+ // Act & Assert
97
+ mockMvc.perform(get("/api/users/" + user.getId()))
98
+ .andExpect(status().isOk())
99
+ .andExpect(jsonPath("$.name").value("John"));
100
+ }
101
+ }
102
+ ```
103
+
104
+ **适用场景**:
105
+ - 端到端测试
106
+ - 加载完整 Spring 上下文
107
+ - 速度慢,但测试最全面
108
+
109
+ ### 选择指南
110
+
111
+ | 模式 | 加载范围 | 速度 | 适用场景 |
112
+ |------|---------|------|---------|
113
+ | standaloneSetup | 只加载 Controller | 最快 | Controller 单元测试 |
114
+ | @WebMvcTest | Web 层 | 快 | Controller 集成测试 |
115
+ | @SpringBootTest | 全上下文 | 慢 | 端到端测试 |
116
+
117
+ ---
118
+
119
+ ## 2. @Transactional 测试
120
+
121
+ ### 同步操作
122
+
123
+ ```java
124
+ @SpringBootTest
125
+ @Transactional
126
+ class UserServiceTest {
127
+
128
+ @Autowired
129
+ private UserService userService;
130
+
131
+ @Autowired
132
+ private UserRepository userRepository;
133
+
134
+ @Test
135
+ void testCreateUser() {
136
+ // Arrange
137
+ CreateUserRequest request = new CreateUserRequest("John", "john@example.com");
138
+
139
+ // Act
140
+ User user = userService.createUser(request);
141
+
142
+ // Assert
143
+ assertNotNull(user.getId());
144
+ assertEquals("John", user.getName());
145
+ }
146
+ // 测试结束后自动回滚
147
+ }
148
+ ```
149
+
150
+ ### 异步操作(不适用 @Transactional)
151
+
152
+ ```java
153
+ @SpringBootTest
154
+ class UserServiceAsyncTest {
155
+
156
+ @Autowired
157
+ private UserService userService;
158
+
159
+ @Autowired
160
+ private RabbitTemplate rabbitTemplate;
161
+
162
+ @AfterEach
163
+ void cleanup() {
164
+ // 手动清空消息队列
165
+ rabbitTemplate.execute(channel -> {
166
+ channel.queuePurge("user-events");
167
+ return null;
168
+ });
169
+ }
170
+
171
+ @Test
172
+ void testCreateUserSendsEvent() {
173
+ // Arrange
174
+ CreateUserRequest request = new CreateUserRequest("John", "john@example.com");
175
+
176
+ // Act
177
+ User user = userService.createUser(request);
178
+
179
+ // Assert
180
+ assertNotNull(user.getId());
181
+
182
+ // 验证消息发送
183
+ Message message = rabbitTemplate.receive("user-events", 1000);
184
+ assertNotNull(message);
185
+ }
186
+ }
187
+ ```
188
+
189
+ ---
190
+
191
+ ## 3. 测试隔离
192
+
193
+ ### Repository 层:H2 内存库
194
+
195
+ ```java
196
+ @DataJpaTest
197
+ class UserRepositoryTest {
198
+
199
+ @Autowired
200
+ private UserRepository userRepository;
201
+
202
+ @Test
203
+ void testFindByEmail() {
204
+ // Arrange
205
+ User user = new User("John", "john@example.com");
206
+ userRepository.save(user);
207
+
208
+ // Act
209
+ Optional<User> found = userRepository.findByEmail("john@example.com");
210
+
211
+ // Assert
212
+ assertTrue(found.isPresent());
213
+ assertEquals("John", found.get().getName());
214
+ }
215
+ }
216
+ ```
217
+
218
+ **H2 配置**(application-test.yml):
219
+ ```yaml
220
+ spring:
221
+ datasource:
222
+ url: jdbc:h2:mem:testdb;MODE=MySQL;DATABASE_TO_UPPER=false
223
+ driver-class-name: org.h2.Driver
224
+ jpa:
225
+ hibernate:
226
+ ddl-auto: create-drop
227
+ ```
228
+
229
+ ### Service 层:@Transactional 或手动清理
230
+
231
+ **同步操作**:
232
+ ```java
233
+ @SpringBootTest
234
+ @Transactional
235
+ class UserServiceTest {
236
+ // ...
237
+ }
238
+ ```
239
+
240
+ **异步操作**:
241
+ ```java
242
+ @SpringBootTest
243
+ class UserServiceAsyncTest {
244
+ @AfterEach
245
+ void cleanup() {
246
+ // 手动清理消息队列、缓存等
247
+ }
248
+ }
249
+ ```
250
+
251
+ ### API 层:MockMvc + @Transactional
252
+
253
+ ```java
254
+ @WebMvcTest(UserController.class)
255
+ @Transactional
256
+ class UserControllerTest {
257
+ // ...
258
+ }
259
+ ```
260
+
261
+ ---
262
+
263
+ ## 4. Mock 规范
264
+
265
+ ### @MockBean 使用规范
266
+
267
+ ```java
268
+ @WebMvcTest(UserController.class)
269
+ class UserControllerTest {
270
+
271
+ @MockBean
272
+ private UserService userService;
273
+
274
+ @MockBean
275
+ private EmailService emailService;
276
+
277
+ // ...
278
+ }
279
+ ```
280
+
281
+ **规则**:
282
+ - ✅ 只 mock 外部依赖(外部 API、第三方服务)
283
+ - ✅ 内部依赖尽量用真实实现
284
+ - ❌ 不要过度 mock(会导致测试失去意义)
285
+
286
+ ### @SpyBean 使用规范
287
+
288
+ ```java
289
+ @SpringBootTest
290
+ class UserServiceTest {
291
+
292
+ @SpyBean
293
+ private UserService userService;
294
+
295
+ @Test
296
+ void testCreateUser() {
297
+ // Arrange
298
+ doReturn(new User("John")).when(userService).generateUser(any());
299
+
300
+ // Act
301
+ User user = userService.createUser(new CreateUserRequest("John"));
302
+
303
+ // Assert
304
+ assertEquals("John", user.getName());
305
+ verify(userService).generateUser(any());
306
+ }
307
+ }
308
+ ```
309
+
310
+ **适用场景**:
311
+ - 需要部分 mock(只 mock 某个方法)
312
+ - 需要验证方法调用次数
313
+
314
+ ---
315
+
316
+ ## 5. 测试配置
317
+
318
+ ### application-test.yml
319
+
320
+ ```yaml
321
+ spring:
322
+ # 数据库
323
+ datasource:
324
+ url: jdbc:h2:mem:testdb;MODE=MySQL;DATABASE_TO_UPPER=false
325
+ driver-class-name: org.h2.Driver
326
+ jpa:
327
+ hibernate:
328
+ ddl-auto: create-drop
329
+
330
+ # 消息队列
331
+ rabbitmq:
332
+ host: localhost
333
+ port: 5672
334
+ username: guest
335
+ password: guest
336
+
337
+ # Redis
338
+ redis:
339
+ host: localhost
340
+ port: 6378
341
+
342
+ # 日志
343
+ logging:
344
+ level:
345
+ root: INFO
346
+ com.example: DEBUG
347
+ ```
348
+
349
+ ### 测试 Profile
350
+
351
+ ```java
352
+ @SpringBootTest
353
+ @ActiveProfiles("test")
354
+ class UserServiceTest {
355
+ // ...
356
+ }
357
+ ```
358
+
359
+ ---
360
+
361
+ ## 6. 常见问题
362
+
363
+ ### 1. @Transactional 不回滚
364
+
365
+ **原因**:
366
+ - 异步操作(@Async、消息队列)
367
+ - 多数据源
368
+ - 自定义事务管理器
369
+
370
+ **解决方案**:
371
+ - 异步操作:手动清理
372
+ - 多数据源:@Transactional("transactionManagerName")
373
+ - 自定义事务管理器:确保测试使用正确的管理器
374
+
375
+ ### 2. @MockBean 影响其他测试
376
+
377
+ **原因**:
378
+ - @MockBean 会重新加载 Spring 上下文
379
+ - 大量使用 @MockBean 会导致测试变慢
380
+
381
+ **解决方案**:
382
+ - 使用 standaloneSetup 替代 @WebMvcTest
383
+ - 使用 @SpyBean 替代 @MockBean(部分 mock)
384
+ - 合并相似的测试用例
385
+
386
+ ### 3. 测试数据污染
387
+
388
+ **原因**:
389
+ - 测试数据泄漏到其他测试
390
+ - 数据库状态不一致
391
+
392
+ **解决方案**:
393
+ - 使用 @Transactional 自动回滚
394
+ - 使用 @DirtContexts 标记需要重新加载上下文的测试
395
+ - 每个测试独立数据(Builder 模式)
396
+
397
+ ---
398
+
399
+ ## 7. 与 glaf4-test 的关系
400
+
401
+ 本规范参考了 glaf4-test 的以下要求:
402
+ - MockMvc 三模式:standaloneSetup / @WebMvcTest / @SpringBootTest
403
+ - H2 内存库:`MODE=MySQL;DATABASE_TO_UPPER=false`
404
+ - @Transactional 测试:同步操作自动回滚
405
+ - @MockBean 规范:只 mock 外部依赖
406
+
407
+ **注意**:glaf4-test 的部分配置是 GLAF4 框架专用的(如 `gtmc.glaf4.*` 配置键),本规范已抽象为通用模式。
408
+
409
+ ---
410
+
411
+ ## 变更记录
412
+
413
+ | 日期 | 版本 | 变更内容 |
414
+ |------|------|---------|
415
+ | 2026-08-04 | v1.0 | 初始版本,符合 glaf4-test 要求 |
@@ -0,0 +1,261 @@
1
+ ---
2
+ name: js-testing
3
+ version: 1.0.0
4
+ updated_at: 2026-08-04
5
+ source: team-flow plugin
6
+ description: JavaScript 测试规范(Jest/Vitest)
7
+ tech_stack: [javascript, jest, vitest]
8
+ glaf4_compliant: false
9
+ ---
10
+
11
+ # JavaScript 测试规范
12
+
13
+ ---
14
+
15
+ ## 1. 测试结构
16
+
17
+ ### Jest / Vitest
18
+
19
+ ```javascript
20
+ describe('UserService', () => {
21
+ describe('getUser', () => {
22
+ it('should return user when id exists', async () => {
23
+ // Arrange
24
+ const userId = 1;
25
+ const expectedUser = { id: 1, name: 'John' };
26
+ userRepository.findById.mockResolvedValue(expectedUser);
27
+
28
+ // Act
29
+ const user = await userService.getUser(userId);
30
+
31
+ // Assert
32
+ expect(user).toEqual(expectedUser);
33
+ expect(userRepository.findById).toHaveBeenCalledWith(userId);
34
+ });
35
+
36
+ it('should throw error when id not found', async () => {
37
+ // Arrange
38
+ const userId = 999;
39
+ userRepository.findById.mockResolvedValue(null);
40
+
41
+ // Act & Assert
42
+ await expect(userService.getUser(userId)).rejects.toThrow('User not found');
43
+ });
44
+ });
45
+ });
46
+ ```
47
+
48
+ ---
49
+
50
+ ## 2. Mock 规范
51
+
52
+ ### Jest
53
+
54
+ ```javascript
55
+ // 自动 mock
56
+ jest.mock('./userRepository');
57
+
58
+ // 手动 mock
59
+ const mockUserRepository = {
60
+ findById: jest.fn(),
61
+ save: jest.fn(),
62
+ };
63
+
64
+ // mock 实现
65
+ mockUserRepository.findById.mockResolvedValue({ id: 1, name: 'John' });
66
+
67
+ // 验证调用
68
+ expect(mockUserRepository.findById).toHaveBeenCalledWith(1);
69
+ expect(mockUserRepository.findById).toHaveBeenCalledTimes(1);
70
+ ```
71
+
72
+ ### Vitest
73
+
74
+ ```javascript
75
+ import { vi } from 'vitest';
76
+
77
+ // 自动 mock
78
+ vi.mock('./userRepository');
79
+
80
+ // 手动 mock
81
+ const mockUserRepository = {
82
+ findById: vi.fn(),
83
+ save: vi.fn(),
84
+ };
85
+
86
+ // mock 实现
87
+ mockUserRepository.findById.mockResolvedValue({ id: 1, name: 'John' });
88
+
89
+ // 验证调用
90
+ expect(mockUserRepository.findById).toHaveBeenCalledWith(1);
91
+ expect(mockUserRepository.findById).toHaveBeenCalledTimes(1);
92
+ ```
93
+
94
+ ---
95
+
96
+ ## 3. 断言规范
97
+
98
+ ### expect 常用方法
99
+
100
+ ```javascript
101
+ // 相等
102
+ expect(value).toBe(expected);
103
+ expect(value).toEqual(expected);
104
+
105
+ // 真假
106
+ expect(value).toBeTruthy();
107
+ expect(value).toBeFalsy();
108
+ expect(value).toBeNull();
109
+ expect(value).toBeUndefined();
110
+
111
+ // 数字
112
+ expect(value).toBeGreaterThan(0);
113
+ expect(value).toBeLessThan(100);
114
+
115
+ // 字符串
116
+ expect(value).toMatch(/pattern/);
117
+ expect(value).toContain('substring');
118
+
119
+ // 数组
120
+ expect(array).toContain(item);
121
+ expect(array).toHaveLength(3);
122
+
123
+ // 对象
124
+ expect(object).toHaveProperty('key', 'value');
125
+
126
+ // 异常
127
+ expect(() => fn()).toThrow('error message');
128
+ await expect(promise).rejects.toThrow('error message');
129
+ ```
130
+
131
+ ### 禁止无意义断言
132
+
133
+ ```javascript
134
+ // ❌ 违规
135
+ test('test something', () => {
136
+ expect(true).toBe(true);
137
+ });
138
+
139
+ // ✅ 正确
140
+ test('should return user', () => {
141
+ const user = getUser(1);
142
+ expect(user).toEqual({ id: 1, name: 'John' });
143
+ });
144
+ ```
145
+
146
+ ---
147
+
148
+ ## 4. 异步测试
149
+
150
+ ### async/await
151
+
152
+ ```javascript
153
+ test('should fetch user', async () => {
154
+ const user = await userService.getUser(1);
155
+ expect(user).toEqual({ id: 1, name: 'John' });
156
+ });
157
+
158
+ test('should throw error', async () => {
159
+ await expect(userService.getUser(999)).rejects.toThrow('User not found');
160
+ });
161
+ ```
162
+
163
+ ### 回调
164
+
165
+ test('should call callback', (done) => {
166
+ userService.getUser(1, (user) => {
167
+ expect(user).toEqual({ id: 1, name: 'John' });
168
+ done();
169
+ });
170
+ });
171
+ ```
172
+
173
+ ---
174
+
175
+ ## 5. 测试数据
176
+
177
+ ### Builder 模式
178
+
179
+ ```javascript
180
+ const userBuilder = (overrides = {}) => ({
181
+ id: 1,
182
+ name: 'John',
183
+ email: 'john@example.com',
184
+ ...overrides,
185
+ });
186
+
187
+ test('should create user', () => {
188
+ const userData = userBuilder({ name: 'Jane' });
189
+ const user = await userService.createUser(userData);
190
+ expect(user.name).toBe('Jane');
191
+ });
192
+ ```
193
+
194
+ ### Fixture
195
+
196
+ ```javascript
197
+ // fixtures/users.json
198
+ [
199
+ { "id": 1, "name": "John" },
200
+ { "id": 2, "name": "Jane" }
201
+ ]
202
+
203
+ // test
204
+ import users from './fixtures/users.json';
205
+
206
+ test('should return all users', () => {
207
+ const result = userService.getAllUsers();
208
+ expect(result).toEqual(users);
209
+ });
210
+ ```
211
+
212
+ ---
213
+
214
+ ## 6. 测试隔离
215
+
216
+ ### 每个测试独立
217
+
218
+ ```javascript
219
+ describe('UserService', () => {
220
+ let userService;
221
+ let mockUserRepository;
222
+
223
+ beforeEach(() => {
224
+ mockUserRepository = {
225
+ findById: jest.fn(),
226
+ save: jest.fn(),
227
+ };
228
+ userService = new UserService(mockUserRepository);
229
+ });
230
+
231
+ afterEach(() => {
232
+ jest.clearAllMocks();
233
+ });
234
+
235
+ test('should return user', async () => {
236
+ mockUserRepository.findById.mockResolvedValue({ id: 1, name: 'John' });
237
+ const user = await userService.getUser(1);
238
+ expect(user).toEqual({ id: 1, name: 'John' });
239
+ });
240
+ });
241
+ ```
242
+
243
+ ---
244
+
245
+ ## 7. 测试质量规则
246
+
247
+ 参见 `references/test-quality-rules.md`,主要包括:
248
+
249
+ 1. 断言质量规则(missing-meaningful-assertion、weak-assertion-only)
250
+ 2. 调试代码残留规则(console.log)
251
+ 3. 测试状态规则(test.skip、test.todo)
252
+ 4. 测试数据规则(hardcoded-sample-like-value、real-external-url)
253
+ 5. 测试结构规则(large-test-file、generic-test-name)
254
+
255
+ ---
256
+
257
+ ## 变更记录
258
+
259
+ | 日期 | 版本 | 变更内容 |
260
+ |------|------|---------|
261
+ | 2026-08-04 | v1.0 | 初始版本 |