@martinffx/atelier 2.0.0 → 3.0.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 (81) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +94 -253
  3. package/package.json +1 -1
  4. package/skills/{spec-orchestrator → atelier-orchestrator}/SKILL.md +3 -3
  5. package/skills/atelier-setup/SKILL.md +80 -0
  6. package/skills/code-review/references/reviewers.md +3 -3
  7. package/skills/code-review/references/rq.md +6 -6
  8. package/skills/spec-brainstorm/SKILL.md +5 -5
  9. package/skills/spec-implement/SKILL.md +2 -3
  10. package/skills/spec-plan/SKILL.md +21 -29
  11. package/skills/spec-plan/references/plan_template.md +77 -0
  12. package/skills/python-architecture/SKILL.md +0 -148
  13. package/skills/python-architecture/references/data-modeling.md +0 -558
  14. package/skills/python-architecture/references/ddd.md +0 -569
  15. package/skills/python-architecture/references/functional-core.md +0 -337
  16. package/skills/python-build-tools/SKILL.md +0 -153
  17. package/skills/python-build-tools/references/basedpyright.md +0 -321
  18. package/skills/python-build-tools/references/ruff.md +0 -225
  19. package/skills/python-build-tools/references/uv.md +0 -257
  20. package/skills/python-fastapi/SKILL.md +0 -184
  21. package/skills/python-fastapi/references/api-design.md +0 -563
  22. package/skills/python-fastapi/references/dependencies.md +0 -479
  23. package/skills/python-fastapi/references/middleware.md +0 -475
  24. package/skills/python-fastapi/references/validation.md +0 -497
  25. package/skills/python-modern-python/SKILL.md +0 -201
  26. package/skills/python-modern-python/references/async.md +0 -76
  27. package/skills/python-modern-python/references/pattern-matching.md +0 -89
  28. package/skills/python-modern-python/references/typing.md +0 -96
  29. package/skills/python-monorepo/SKILL.md +0 -146
  30. package/skills/python-monorepo/references/docker.md +0 -515
  31. package/skills/python-monorepo/references/namespace-packages.md +0 -426
  32. package/skills/python-monorepo/references/workspace-config.md +0 -341
  33. package/skills/python-sqlalchemy/SKILL.md +0 -119
  34. package/skills/python-sqlalchemy/references/async.md +0 -51
  35. package/skills/python-sqlalchemy/references/models.md +0 -67
  36. package/skills/python-sqlalchemy/references/queries.md +0 -57
  37. package/skills/python-temporal/SKILL.md +0 -128
  38. package/skills/python-temporal/references/patterns.md +0 -87
  39. package/skills/python-temporal/references/testing.md +0 -54
  40. package/skills/python-testing/SKILL.md +0 -161
  41. package/skills/python-testing/references/boundaries.md +0 -449
  42. package/skills/python-testing/references/mocking.md +0 -449
  43. package/skills/python-testing/references/pytest.md +0 -524
  44. package/skills/typescript-api-design/SKILL.md +0 -396
  45. package/skills/typescript-api-design/references/error-responses.md +0 -469
  46. package/skills/typescript-build-tools/SKILL.md +0 -447
  47. package/skills/typescript-build-tools/references/biome.md +0 -436
  48. package/skills/typescript-build-tools/references/bun.md +0 -432
  49. package/skills/typescript-build-tools/references/turborepo.md +0 -426
  50. package/skills/typescript-build-tools/references/vitest.md +0 -518
  51. package/skills/typescript-drizzle-orm/SKILL.md +0 -398
  52. package/skills/typescript-drizzle-orm/references/cloudflare.md +0 -392
  53. package/skills/typescript-drizzle-orm/references/entity-pattern.md +0 -412
  54. package/skills/typescript-drizzle-orm/references/postgresql.md +0 -191
  55. package/skills/typescript-drizzle-orm/references/repository-pattern.md +0 -479
  56. package/skills/typescript-drizzle-orm/references/sqlite.md +0 -291
  57. package/skills/typescript-dynamodb-toolbox/SKILL.md +0 -370
  58. package/skills/typescript-dynamodb-toolbox/references/entity-layer.md +0 -574
  59. package/skills/typescript-dynamodb-toolbox/references/error-handling.md +0 -495
  60. package/skills/typescript-dynamodb-toolbox/references/modeling.md +0 -332
  61. package/skills/typescript-dynamodb-toolbox/references/repository-layer.md +0 -631
  62. package/skills/typescript-dynamodb-toolbox/references/testing.md +0 -718
  63. package/skills/typescript-dynamodb-toolbox/references/transactions.md +0 -423
  64. package/skills/typescript-effect-ts/SKILL.md +0 -341
  65. package/skills/typescript-effect-ts/references/core.md +0 -412
  66. package/skills/typescript-effect-ts/references/error-handling.md +0 -468
  67. package/skills/typescript-effect-ts/references/resources.md +0 -476
  68. package/skills/typescript-effect-ts/references/schema.md +0 -536
  69. package/skills/typescript-effect-ts/references/services.md +0 -461
  70. package/skills/typescript-fastify/SKILL.md +0 -405
  71. package/skills/typescript-fastify/references/plugins.md +0 -329
  72. package/skills/typescript-fastify/references/typeid.md +0 -315
  73. package/skills/typescript-functional-patterns/SKILL.md +0 -402
  74. package/skills/typescript-functional-patterns/references/adts.md +0 -497
  75. package/skills/typescript-functional-patterns/references/branded-types.md +0 -542
  76. package/skills/typescript-functional-patterns/references/migration-guide.md +0 -695
  77. package/skills/typescript-functional-patterns/references/option-result.md +0 -585
  78. package/skills/typescript-testing/SKILL.md +0 -353
  79. package/skills/typescript-testing/references/mocking.md +0 -675
  80. package/skills/typescript-testing/references/msw.md +0 -852
  81. package/skills/typescript-testing/references/snapshot-testing.md +0 -774
@@ -1,449 +0,0 @@
1
- # Mocking and Stubbing Strategies
2
-
3
- Stub external dependencies to isolate units under test. Use at layer boundaries.
4
-
5
- ## unittest.mock Basics
6
-
7
- ### Mock Objects
8
-
9
- ```python
10
- from unittest.mock import Mock
11
-
12
- # Create mock
13
- mock_repo = Mock()
14
-
15
- # Configure return value
16
- mock_repo.get.return_value = User(id=1, name="Alice")
17
-
18
- # Call mock
19
- user = mock_repo.get(1)
20
-
21
- # Verify it was called
22
- mock_repo.get.assert_called_once_with(1)
23
- ```
24
-
25
- ### MagicMock for Chaining
26
-
27
- ```python
28
- from unittest.mock import MagicMock
29
-
30
- # MagicMock supports method chaining
31
- mock_db = MagicMock()
32
- mock_db.query.return_value.filter.return_value.first.return_value = UserRecord()
33
-
34
- # Chain calls work
35
- user = mock_db.query(User).filter(User.id == 1).first()
36
- assert user is not None
37
- ```
38
-
39
- ### patch Decorator
40
-
41
- ```python
42
- from unittest.mock import patch
43
-
44
- # Patch module-level dependency
45
- @patch("my_module.DatabaseSession")
46
- def test_with_patched_db(mock_db_class):
47
- """Patch is applied for duration of test"""
48
- mock_db_class.return_value = Mock()
49
-
50
- service = UserService() # Gets patched DatabaseSession
51
- # Test code
52
- ```
53
-
54
- ### patch as Context Manager
55
-
56
- ```python
57
- from unittest.mock import patch
58
-
59
- def test_with_patch_context():
60
- """Patch applied only within context"""
61
- with patch("my_module.external_api_call") as mock_api:
62
- mock_api.return_value = {"status": "success"}
63
-
64
- result = process_data()
65
-
66
- assert result["status"] == "success"
67
- ```
68
-
69
- ### spec Parameter
70
-
71
- ```python
72
- from unittest.mock import Mock
73
-
74
- # Mock with spec restricts to real attributes
75
- mock_repo = Mock(spec=UserRepository)
76
-
77
- # This works (real method on UserRepository)
78
- mock_repo.save()
79
-
80
- # This fails with AttributeError (not real method)
81
- with pytest.raises(AttributeError):
82
- mock_repo.invalid_method()
83
- ```
84
-
85
- ## Verification Methods
86
-
87
- ### assert_called_once
88
-
89
- ```python
90
- mock_obj = Mock()
91
-
92
- # Called exactly once
93
- mock_obj.method()
94
- mock_obj.method.assert_called_once()
95
-
96
- # With arguments
97
- mock_obj.method(42, "test")
98
- mock_obj.method.assert_called_once_with(42, "test")
99
- ```
100
-
101
- ### assert_called
102
-
103
- ```python
104
- mock_obj = Mock()
105
-
106
- # Called at least once
107
- mock_obj.method()
108
- mock_obj.method()
109
- mock_obj.method.assert_called() # Passes
110
- ```
111
-
112
- ### assert_called_with
113
-
114
- ```python
115
- mock_obj = Mock()
116
-
117
- # Called with specific arguments
118
- mock_obj.method(1, 2, 3)
119
- mock_obj.method.assert_called_with(1, 2, 3) # Passes
120
-
121
- mock_obj.method.assert_called_with(1, 2) # Fails - wrong args
122
- ```
123
-
124
- ### assert_not_called
125
-
126
- ```python
127
- mock_obj = Mock()
128
-
129
- # Never called
130
- mock_obj.method.assert_not_called() # Passes
131
-
132
- mock_obj.method()
133
- mock_obj.method.assert_not_called() # Fails
134
- ```
135
-
136
- ### call_count
137
-
138
- ```python
139
- mock_obj = Mock()
140
-
141
- mock_obj.method()
142
- mock_obj.method()
143
- mock_obj.method()
144
-
145
- assert mock_obj.method.call_count == 3
146
- ```
147
-
148
- ### Multiple Calls
149
-
150
- ```python
151
- from unittest.mock import call
152
-
153
- mock_obj = Mock()
154
-
155
- mock_obj.method(1)
156
- mock_obj.method(2)
157
- mock_obj.method(3)
158
-
159
- mock_obj.method.assert_has_calls([
160
- call(1),
161
- call(2),
162
- call(3),
163
- ])
164
- ```
165
-
166
- ## pytest-mock Integration
167
-
168
- ### mocker Fixture
169
-
170
- ```python
171
- def test_with_mocker(mocker):
172
- """pytest-mock provides cleaner patching"""
173
- # Patch and get mock in one call
174
- mock_db = mocker.patch("my_module.get_db")
175
- mock_db.return_value = Mock()
176
-
177
- service = UserService()
178
- # Test code
179
- ```
180
-
181
- ### Compared to unittest.mock
182
-
183
- ```python
184
- # unittest.mock (verbose)
185
- @patch("my_module.get_db")
186
- def test_with_patch(mock_db):
187
- mock_db.return_value = Mock()
188
- ...
189
-
190
- # pytest-mock (cleaner)
191
- def test_with_mocker(mocker):
192
- mock_db = mocker.patch("my_module.get_db")
193
- mock_db.return_value = Mock()
194
- ...
195
- ```
196
-
197
- ## Common Mocking Patterns
198
-
199
- ### Service with Mocked Repository
200
-
201
- ```python
202
- def test_create_product_service():
203
- """Mock repository dependency"""
204
- # Create mock
205
- mock_repo = Mock(spec=ProductRepository)
206
- mock_repo.save.return_value = Product(
207
- id=uuid4(),
208
- name="Widget",
209
- price=Decimal("9.99"),
210
- )
211
-
212
- # Create service with mock
213
- service = ProductService(repo=mock_repo)
214
-
215
- # Call service
216
- request = CreateProductRequest(name="Widget", price=Decimal("9.99"))
217
- result = service.create(request)
218
-
219
- # Verify interactions
220
- mock_repo.save.assert_called_once()
221
- assert result.name == "Widget"
222
- ```
223
-
224
- ### Service with Mocked External API
225
-
226
- ```python
227
- @patch("my_module.stripe.charge")
228
- def test_process_payment(mock_stripe):
229
- """Mock external service call"""
230
- mock_stripe.return_value = {"status": "succeeded"}
231
-
232
- service = PaymentService()
233
- result = service.process_payment(Decimal("99.99"))
234
-
235
- mock_stripe.assert_called_once()
236
- assert result["status"] == "succeeded"
237
- ```
238
-
239
- ### Multiple Mocked Dependencies
240
-
241
- ```python
242
- def test_complex_workflow(mocker):
243
- """Multiple mocks in one test"""
244
- mock_repo = mocker.patch("my_module.repository")
245
- mock_api = mocker.patch("my_module.external_api")
246
- mock_logger = mocker.patch("my_module.logger")
247
-
248
- mock_repo.get.return_value = {"id": 1}
249
- mock_api.call.return_value = {"result": "ok"}
250
-
251
- service = ComplexService()
252
- result = service.do_something(1)
253
-
254
- mock_repo.get.assert_called_once_with(1)
255
- mock_api.call.assert_called_once()
256
- mock_logger.info.assert_called()
257
- ```
258
-
259
- ### Side Effects for Complex Behavior
260
-
261
- ```python
262
- def test_with_side_effect():
263
- """Mock returns different values on each call"""
264
- mock_obj = Mock()
265
-
266
- # Return different values
267
- mock_obj.method.side_effect = [1, 2, 3]
268
-
269
- assert mock_obj.method() == 1
270
- assert mock_obj.method() == 2
271
- assert mock_obj.method() == 3
272
-
273
- def test_with_side_effect_exception():
274
- """Mock raises exception"""
275
- mock_obj = Mock()
276
-
277
- # Raise exception on call
278
- mock_obj.method.side_effect = ValueError("Test error")
279
-
280
- with pytest.raises(ValueError, match="Test error"):
281
- mock_obj.method()
282
- ```
283
-
284
- ### Partial Mocking with spec_set
285
-
286
- ```python
287
- class UserRepository:
288
- def get(self, id):
289
- ...
290
-
291
- def save(self, user):
292
- ...
293
-
294
- # spec_set prevents adding new attributes
295
- mock_repo = Mock(spec_set=UserRepository)
296
-
297
- mock_repo.get.return_value = User(id=1)
298
-
299
- # This works
300
- mock_repo.get(1)
301
-
302
- # This fails - not on UserRepository
303
- with pytest.raises(AttributeError):
304
- mock_repo.new_method()
305
- ```
306
-
307
- ## Fixture-Based Mocking
308
-
309
- ### Reusable Mock Fixtures
310
-
311
- ```python
312
- import pytest
313
- from unittest.mock import Mock
314
-
315
- @pytest.fixture
316
- def mock_repository():
317
- """Mock repository fixture"""
318
- mock = Mock(spec=UserRepository)
319
- mock.save.return_value = None
320
- mock.get.return_value = User(id=1, name="Test")
321
- return mock
322
-
323
- @pytest.fixture
324
- def mock_external_api():
325
- """Mock external API fixture"""
326
- mock = Mock()
327
- mock.call.return_value = {"status": "success"}
328
- return mock
329
-
330
- def test_service_with_fixtures(mock_repository, mock_external_api):
331
- """Use mocked dependencies"""
332
- service = UserService(
333
- repo=mock_repository,
334
- api=mock_external_api,
335
- )
336
-
337
- result = service.create_user({"name": "Alice"})
338
-
339
- mock_repository.save.assert_called_once()
340
- assert result is not None
341
- ```
342
-
343
- ## Testing with Real vs Mock Objects
344
-
345
- ### When to Mock
346
-
347
- ```python
348
- # GOOD: Mock external service
349
- @patch("requests.post")
350
- def test_send_notification(mock_post):
351
- """Don't actually call HTTP endpoints"""
352
- mock_post.return_value = Mock(status_code=200)
353
-
354
- service = NotificationService()
355
- result = service.send_email("test@example.com")
356
-
357
- assert result is True
358
- ```
359
-
360
- ### When to Use Real Objects
361
-
362
- ```python
363
- # GOOD: Use real database for repository tests
364
- def test_repository_save(test_db):
365
- """Test actual database behavior"""
366
- repo = UserRepository(test_db)
367
- user = User(id=1, name="Alice")
368
-
369
- repo.save(user)
370
-
371
- # Verify in database
372
- assert test_db.query(UserRecord).count() == 1
373
- ```
374
-
375
- ### Hybrid: Real + Mock
376
-
377
- ```python
378
- def test_service_orchestration(test_db, mocker):
379
- """Real repository, mocked external API"""
380
- # Real database
381
- repo = UserRepository(test_db)
382
-
383
- # Mocked external API
384
- mock_api = mocker.patch("my_module.send_email")
385
-
386
- # Test service orchestration
387
- service = UserService(repo=repo, api=mock_api)
388
- result = service.create_and_notify({"name": "Alice"})
389
-
390
- # Both called
391
- assert test_db.query(UserRecord).count() == 1
392
- mock_api.assert_called_once()
393
- ```
394
-
395
- ## Anti-Patterns to Avoid
396
-
397
- ### Over-Mocking
398
-
399
- ```python
400
- # BAD: Mocking everything
401
- def test_service():
402
- mock_repo = Mock()
403
- mock_entity = Mock()
404
- mock_response = Mock()
405
- # Test is now testing mocks, not code
406
-
407
- # GOOD: Mock at boundaries, use real objects internally
408
- def test_service(test_db):
409
- repo = UserRepository(test_db) # Real
410
- service = UserService(repo) # Real
411
- result = service.get_user(1) # Test actual behavior
412
- ```
413
-
414
- ### Tautological Mocks
415
-
416
- ```python
417
- # BAD: Mock returns what we programmed it to return
418
- def test_something():
419
- mock = Mock()
420
- mock.method.return_value = 42
421
- assert mock.method() == 42 # Always passes, tests nothing
422
-
423
- # GOOD: Test real logic
424
- def test_something():
425
- obj = RealObject()
426
- result = obj.calculate()
427
- assert result == expected
428
- ```
429
-
430
- ### Mock Drift
431
-
432
- ```python
433
- # BAD: Mock doesn't match reality
434
- class RealService:
435
- def process(self, data):
436
- return data.upper()
437
-
438
- def test_service():
439
- mock_service = Mock()
440
- mock_service.process.return_value = "WRONG" # Not what real does
441
-
442
- # Test passes but would fail with real service
443
-
444
- # GOOD: Mock matches real behavior or test with real
445
- def test_service():
446
- service = RealService()
447
- result = service.process("test")
448
- assert result == "TEST"
449
- ```