@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,333 @@
1
+ ---
2
+ name: python-testing
3
+ version: 1.0.0
4
+ updated_at: 2026-08-04
5
+ source: team-flow plugin
6
+ description: Python 测试规范(Pytest)
7
+ tech_stack: [python, pytest]
8
+ glaf4_compliant: false
9
+ ---
10
+
11
+ # Python 测试规范
12
+
13
+ ---
14
+
15
+ ## 1. 测试结构
16
+
17
+ ### Pytest
18
+
19
+ ```python
20
+ class TestUserService:
21
+ def test_get_user_returns_user_when_id_exists(self):
22
+ # Arrange
23
+ user_id = 1
24
+ expected_user = {"id": 1, "name": "John"}
25
+ mock_user_repository.find_by_id.return_value = expected_user
26
+
27
+ # Act
28
+ user = user_service.get_user(user_id)
29
+
30
+ # Assert
31
+ assert user == expected_user
32
+ mock_user_repository.find_by_id.assert_called_once_with(user_id)
33
+
34
+ def test_get_user_raises_error_when_id_not_found(self):
35
+ # Arrange
36
+ user_id = 999
37
+ mock_user_repository.find_by_id.return_value = None
38
+
39
+ # Act & Assert
40
+ with pytest.raises(UserNotFoundError, match="User not found"):
41
+ user_service.get_user(user_id)
42
+ ```
43
+
44
+ ### 命名规范
45
+
46
+ - 测试文件:`test_[module].py`(如 `test_user_service.py`)
47
+ - 测试类:`Test[ClassName]`(如 `TestUserService`)
48
+ - 测试方法:`test_[method]_[scenario]`(如 `test_get_user_returns_user`)
49
+
50
+ ---
51
+
52
+ ## 2. Mock 规范
53
+
54
+ ### unittest.mock
55
+
56
+ ```python
57
+ from unittest.mock import Mock, patch, MagicMock
58
+
59
+ # 创建 Mock
60
+ mock_user_repository = Mock()
61
+ mock_user_repository.find_by_id.return_value = {"id": 1, "name": "John"}
62
+
63
+ # 验证调用
64
+ mock_user_repository.find_by_id.assert_called_once_with(1)
65
+ mock_user_repository.find_by_id.assert_called()
66
+
67
+ # patch 装饰器
68
+ @patch('app.services.user_service.UserRepository')
69
+ def test_get_user(mock_repo_class):
70
+ mock_repo = mock_repo_class.return_value
71
+ mock_repo.find_by_id.return_value = {"id": 1, "name": "John"}
72
+
73
+ user = user_service.get_user(1)
74
+
75
+ assert user == {"id": 1, "name": "John"}
76
+ mock_repo.find_by_id.assert_called_once_with(1)
77
+ ```
78
+
79
+ ### pytest-mock
80
+
81
+ ```python
82
+ def test_get_user(mocker):
83
+ mock_repo = mocker.patch('app.services.user_service.UserRepository')
84
+ mock_repo.find_by_id.return_value = {"id": 1, "name": "John"}
85
+
86
+ user = user_service.get_user(1)
87
+
88
+ assert user == {"id": 1, "name": "John"}
89
+ mock_repo.find_by_id.assert_called_once_with(1)
90
+ ```
91
+
92
+ ---
93
+
94
+ ## 3. 断言规范
95
+
96
+ ### assert 常用方法
97
+
98
+ ```python
99
+ # 相等
100
+ assert value == expected
101
+ assert value != unexpected
102
+
103
+ # 真假
104
+ assert value is True
105
+ assert value is False
106
+ assert value is None
107
+ assert value is not None
108
+
109
+ # 包含
110
+ assert item in collection
111
+ assert substring in string
112
+
113
+ # 异常
114
+ with pytest.raises(ExceptionType, match="message"):
115
+ function_that_raises()
116
+
117
+ # 近似
118
+ assert value == pytest.approx(expected, rel=1e-2)
119
+
120
+ # 类型
121
+ assert isinstance(value, str)
122
+ ```
123
+
124
+ ### 禁止无意义断言
125
+
126
+ ```python
127
+ # ❌ 违规
128
+ def test_something():
129
+ assert True
130
+
131
+ # ✅ 正确
132
+ def test_get_user():
133
+ user = get_user(1)
134
+ assert user == {"id": 1, "name": "John"}
135
+ ```
136
+
137
+ ---
138
+
139
+ ## 4. Fixture
140
+
141
+ ### 定义 Fixture
142
+
143
+ ```python
144
+ import pytest
145
+
146
+ @pytest.fixture
147
+ def user_repository():
148
+ return Mock()
149
+
150
+ @pytest.fixture
151
+ def user_service(user_repository):
152
+ return UserService(user_repository)
153
+
154
+ @pytest.fixture
155
+ def sample_user():
156
+ return {"id": 1, "name": "John", "email": "john@example.com"}
157
+ ```
158
+
159
+ ### 使用 Fixture
160
+
161
+ ```python
162
+ def test_get_user(user_service, user_repository, sample_user):
163
+ user_repository.find_by_id.return_value = sample_user
164
+
165
+ user = user_service.get_user(1)
166
+
167
+ assert user == sample_user
168
+ ```
169
+
170
+ ### Fixture 作用域
171
+
172
+ ```python
173
+ @pytest.fixture(scope="session")
174
+ def database():
175
+ # 整个测试会话只创建一次
176
+ db = create_test_database()
177
+ yield db
178
+ db.drop_all()
179
+
180
+ @pytest.fixture(scope="function")
181
+ def user_service(user_repository):
182
+ # 每个测试函数创建一次
183
+ return UserService(user_repository)
184
+ ```
185
+
186
+ ---
187
+
188
+ ## 5. 参数化测试
189
+
190
+ ### @pytest.mark.parametrize
191
+
192
+ ```python
193
+ @pytest.mark.parametrize("input,expected", [
194
+ (1, "one"),
195
+ (2, "two"),
196
+ (3, "three"),
197
+ ])
198
+ def test_number_to_word(input, expected):
199
+ assert number_to_word(input) == expected
200
+
201
+ @pytest.mark.parametrize("user_id,expected_name", [
202
+ (1, "John"),
203
+ (2, "Jane"),
204
+ (3, "Bob"),
205
+ ])
206
+ def test_get_user(user_id, expected_name, user_service, user_repository):
207
+ user_repository.find_by_id.return_value = {"id": user_id, "name": expected_name}
208
+
209
+ user = user_service.get_user(user_id)
210
+
211
+ assert user["name"] == expected_name
212
+ ```
213
+
214
+ ---
215
+
216
+ ## 6. 异步测试
217
+
218
+ ### pytest-asyncio
219
+
220
+ ```python
221
+ import pytest
222
+
223
+ @pytest.mark.asyncio
224
+ async def test_get_user_async():
225
+ user = await user_service.get_user_async(1)
226
+ assert user == {"id": 1, "name": "John"}
227
+
228
+ @pytest.mark.asyncio
229
+ async def test_get_user_async_raises_error():
230
+ with pytest.raises(UserNotFoundError):
231
+ await user_service.get_user_async(999)
232
+ ```
233
+
234
+ ---
235
+
236
+ ## 7. 测试数据
237
+
238
+ ### Factory 模式
239
+
240
+ ```python
241
+ import factory
242
+
243
+ class UserFactory(factory.Factory):
244
+ class Meta:
245
+ model = User
246
+
247
+ id = factory.Sequence(lambda n: n + 1)
248
+ name = factory.Faker('name')
249
+ email = factory.Faker('email')
250
+
251
+ # 使用
252
+ def test_get_user():
253
+ user = UserFactory(name="John")
254
+ assert user.name == "John"
255
+ ```
256
+
257
+ ### Fixture
258
+
259
+ ```python
260
+ @pytest.fixture
261
+ def sample_user():
262
+ return User(id=1, name="John", email="john@example.com")
263
+
264
+ @pytest.fixture
265
+ def sample_users():
266
+ return [
267
+ User(id=1, name="John", email="john@example.com"),
268
+ User(id=2, name="Jane", email="jane@example.com"),
269
+ ]
270
+ ```
271
+
272
+ ---
273
+
274
+ ## 8. 测试隔离
275
+
276
+ ### 数据库测试
277
+
278
+ ```python
279
+ @pytest.fixture
280
+ def database():
281
+ # 创建测试数据库
282
+ db = create_test_database()
283
+ yield db
284
+ # 清理
285
+ db.drop_all()
286
+
287
+ @pytest.fixture
288
+ def session(database):
289
+ # 创建事务
290
+ session = database.session()
291
+ session.begin()
292
+ yield session
293
+ # 回滚
294
+ session.rollback()
295
+
296
+ def test_create_user(session, user_repository):
297
+ user = User(name="John", email="john@example.com")
298
+ user_repository.save(user)
299
+
300
+ found = user_repository.find_by_id(user.id)
301
+ assert found.name == "John"
302
+ # 测试结束后自动回滚
303
+ ```
304
+
305
+ ### 外部服务 Mock
306
+
307
+ ```python
308
+ @pytest.fixture
309
+ def mock_external_api(mocker):
310
+ mock = mocker.patch('app.services.external_api_client.ExternalApiClient')
311
+ mock.get_data.return_value = {"status": "ok"}
312
+ return mock
313
+ ```
314
+
315
+ ---
316
+
317
+ ## 9. 测试质量规则
318
+
319
+ 参见 `references/test-quality-rules.md`,主要包括:
320
+
321
+ 1. 断言质量规则(missing-meaningful-assertion、weak-assertion-only)
322
+ 2. 调试代码残留规则(print)
323
+ 3. 测试状态规则(pytest.mark.skip、pytest.mark.xfail)
324
+ 4. 测试数据规则(hardcoded-sample-like-value、real-external-url)
325
+ 5. 测试结构规则(large-test-file、generic-test-name)
326
+
327
+ ---
328
+
329
+ ## 变更记录
330
+
331
+ | 日期 | 版本 | 变更内容 |
332
+ |------|------|---------|
333
+ | 2026-08-04 | v1.0 | 初始版本 |