aw-spec-cli 0.1.10 → 0.1.11

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 (58) hide show
  1. package/assets/.appweaver/ORCH-DIALECT.md +17 -5
  2. package/assets/.appweaver/orchestrator/README.md +1 -1
  3. package/assets/.appweaver/orchestrator/adapters/claude_agent_sdk.py +2 -2
  4. package/assets/.appweaver/orchestrator/adapters/google_antigravity.py +28 -6
  5. package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +13 -1
  6. package/assets/.appweaver/orchestrator/orchestrator.py +126 -39
  7. package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +5 -0
  8. package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +1 -0
  9. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +1 -0
  10. package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +888 -141
  11. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +826 -16
  12. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +780 -12
  13. package/assets/.appweaver/stack-profiles/java-spring.json +3 -3
  14. package/assets/.appweaver/templates/spec-template.md +73 -62
  15. package/assets/.appweaver/templates/story-template.md +107 -0
  16. package/assets/guardrails/technology/java-spring/ai-rules.md +505 -0
  17. package/assets/guardrails/technology/java-spring/api-versioning.md +782 -0
  18. package/assets/guardrails/technology/java-spring/authorization.md +618 -0
  19. package/assets/guardrails/technology/java-spring/clean-architecture.md +960 -0
  20. package/assets/guardrails/technology/java-spring/coding-standards.md +821 -0
  21. package/assets/guardrails/technology/java-spring/dependency-policy.md +91 -0
  22. package/assets/guardrails/technology/java-spring/domain-driven-design.md +467 -0
  23. package/assets/guardrails/technology/java-spring/domain_abstraction.md +424 -0
  24. package/assets/guardrails/technology/java-spring/folder-structure.md +1537 -0
  25. package/assets/guardrails/technology/java-spring/global_exception_handler.md +247 -0
  26. package/assets/guardrails/technology/java-spring/logging.md +215 -0
  27. package/assets/guardrails/technology/java-spring/modular-monolith.md +77 -0
  28. package/assets/guardrails/technology/java-spring/persistence.md +316 -0
  29. package/assets/guardrails/technology/java-spring/problem_details.md +98 -0
  30. package/assets/guardrails/technology/java-spring/result_mapping.md +48 -0
  31. package/assets/guardrails/technology/java-spring/technology-constitution.md +168 -0
  32. package/assets/guardrails/technology/java-spring/testing.md +601 -0
  33. package/assets/guardrails/technology/java-spring/zero-trust.md +210 -0
  34. package/dist/index.js +0 -0
  35. package/dist/utils/config.d.ts +22 -0
  36. package/dist/utils/config.d.ts.map +1 -0
  37. package/dist/utils/config.js +76 -0
  38. package/dist/utils/config.js.map +1 -0
  39. package/dist/utils/copy-assets.d.ts.map +1 -1
  40. package/dist/utils/copy-assets.js +4 -11
  41. package/dist/utils/copy-assets.js.map +1 -1
  42. package/dist/utils/paths.d.ts.map +1 -1
  43. package/dist/utils/paths.js +11 -7
  44. package/dist/utils/paths.js.map +1 -1
  45. package/package.json +2 -1
  46. package/assets/guardrails/technology/java-spring/README.md +0 -62
  47. package/dist/commands/update.d.ts +0 -3
  48. package/dist/commands/update.d.ts.map +0 -1
  49. package/dist/commands/update.js +0 -142
  50. package/dist/commands/update.js.map +0 -1
  51. package/dist/utils/manifest.d.ts +0 -31
  52. package/dist/utils/manifest.d.ts.map +0 -1
  53. package/dist/utils/manifest.js +0 -91
  54. package/dist/utils/manifest.js.map +0 -1
  55. package/dist/utils/update-engine.d.ts +0 -52
  56. package/dist/utils/update-engine.d.ts.map +0 -1
  57. package/dist/utils/update-engine.js +0 -203
  58. package/dist/utils/update-engine.js.map +0 -1
@@ -0,0 +1,601 @@
1
+ # Testing Strategy — Java · DDD · Hexagonal Architecture (Ports & Adapters)
2
+
3
+ > **Domain-agnostic.** This document defines testing standards applicable to any Java project
4
+ > structured around Domain-Driven Design and Hexagonal Architecture.
5
+
6
+ ---
7
+
8
+ ## 1. Core Philosophy
9
+
10
+ | Principle | Rule |
11
+ |-----------|------|
12
+ | **Test-First Engineering** | Tests MUST be written and verified to fail before the production change is in place. |
13
+ | **Right test at the right level** | Domain logic → pure unit tests. Application orchestration → unit tests. Adapter logic → integration/slice tests. No cross-layer leakage. |
14
+ | **Tests as executable specification** | Test names describe business behaviour or externally observable technical behaviour, not implementation details. |
15
+ | **Determinism** | Time, randomness, and identity generation are always injected. Production code MUST NOT directly create non-deterministic values inside business/application logic. |
16
+ | **Same-commit discipline** | Any change to an aggregate invariant, port contract, Result contract, or error representation MUST include the corresponding test update in the same commit. |
17
+ | **No production data in tests** | Tests use synthetic fixture data only. Production data MUST NOT appear in development, test, demo, or CI environments. |
18
+
19
+ ---
20
+
21
+ ## 2. Architecture Layers and Their Test Owners
22
+
23
+ ```text
24
+ ┌──────────────────────────────────────────────────┐
25
+ │ Driving Adapters (Primary) │
26
+ │ [ Controller Slice Tests / E2E ] │
27
+ ├──────────────────────────────────────────────────┤
28
+ │ Application Layer (Use Cases) │
29
+ │ [ Application Service Unit Tests ] │
30
+ ├──────────────────────────────────────────────────┤
31
+ │ Domain Layer (Core) │
32
+ │ [ Pure Domain Unit Tests ] │
33
+ ├──────────────────────────────────────────────────┤
34
+ │ Driven Adapters (Secondary) │
35
+ │ [ Persistence / Adapter Integration ] │
36
+ └──────────────────────────────────────────────────┘
37
+ ````
38
+
39
+ Domain unit tests MUST remain framework-independent.
40
+
41
+ Application unit tests SHOULD remain independent of Spring infrastructure wherever the
42
+ application implementation permits it. Spring-specific wiring is tested separately through
43
+ appropriate integration or slice tests.
44
+
45
+ Driven adapters are tested against real infrastructure through Testcontainers where
46
+ infrastructure behaviour is relevant. H2 MUST NOT be used as a substitute for PostgreSQL
47
+ integration testing.
48
+
49
+ ---
50
+
51
+ ## 3. Test Types Reference
52
+
53
+ | Test Type | Layer | Framework | Spring Context | I/O |
54
+ | ------------------------ | ------------------- | -------------------------------------------- | -------------- | ------------------- |
55
+ | Domain unit | Domain | JUnit 5 | ❌ None | ❌ None |
56
+ | Application service unit | Application | JUnit 5 + Mockito | ❌ None | ❌ Mocked ports only |
57
+ | Controller slice | Primary Adapter | `@WebMvcTest` + MockMvc | ✅ Slice | ❌ Use case mocked |
58
+ | Persistence integration | Secondary Adapter | `@DataJpaTest` + Testcontainers | ✅ Slice | ✅ Real DB |
59
+ | Full integration | All layers | `@SpringBootTest` + Testcontainers | ✅ Full | ✅ Real DB |
60
+ | Architecture | Cross-cutting | ArchUnit | ❌ None | ❌ None |
61
+ | Result Mapping | HTTP/Infrastructure | JUnit 5 + Spring test support where required | As required | Usually ❌ |
62
+ | Problem Details | HTTP/Infrastructure | JUnit 5 + MockMvc where required | As required | Usually ❌ |
63
+
64
+ ---
65
+
66
+ ## 4. Domain Unit Tests
67
+
68
+ ### Rules
69
+
70
+ * No Spring context. No Mockito. No I/O.
71
+ * Test every aggregate **state transition**, **invariant enforcement**, and **domain event emission**.
72
+ * Test every **value object**: construction, equality, and rejection of invalid values.
73
+ * Test every **domain specification / policy**.
74
+ * Use only plain Java and the domain model itself.
75
+ * Domain tests MUST NOT depend on Result Mapping, Problem Details, HTTP, Spring Web, SLF4J, Logback, or other infrastructure concerns.
76
+
77
+ ### Mandatory Coverage
78
+
79
+ * Every aggregate command method → at least one positive and one negative test.
80
+ * Every value object constructor with invalid input → rejection verified.
81
+ * Every invariant violation → appropriate domain failure behaviour verified.
82
+ * Every domain event-producing behaviour → event emission verified.
83
+
84
+ The exact failure representation MUST follow the application's established domain error model.
85
+ Tests MUST NOT require exceptions merely because a scenario represents failure if the application
86
+ uses explicit Result-based failure semantics.
87
+
88
+ ### Naming Convention
89
+
90
+ ```text
91
+ should_[expected outcome]_when_[condition]
92
+ ```
93
+
94
+ ### Determinism Rule
95
+
96
+ Time and identity generation MUST be injectable when required by the system under test.
97
+
98
+ Use `java.time.Clock` directly where appropriate, or an application-defined time abstraction when
99
+ additional control is required.
100
+
101
+ Example:
102
+
103
+ ```java
104
+ Clock fixedClock =
105
+ Clock.fixed(
106
+ Instant.parse("2025-01-01T00:00:00Z"),
107
+ ZoneOffset.UTC
108
+ );
109
+
110
+ IdGenerator fixedIds =
111
+ () -> UUID.fromString("00000000-0000-0000-0000-000000000001");
112
+ ```
113
+
114
+ Production domain/application code MUST NOT directly call:
115
+
116
+ ```java
117
+ LocalDateTime.now();
118
+ Instant.now();
119
+ UUID.randomUUID();
120
+ ```
121
+
122
+ when doing so would make business/application behaviour non-deterministic.
123
+
124
+ ### Structure Example
125
+
126
+ ```java
127
+ @DisplayName("Registration Aggregate")
128
+ class RegistrationTest {
129
+
130
+ @Test
131
+ void should_reject_registration_when_capacity_is_full() {
132
+
133
+ // Arrange
134
+ var event =
135
+ EventBuilder.anEventWithCapacity(1)
136
+ .withOneExistingRegistration()
137
+ .build();
138
+
139
+ // Act
140
+ var result = event.register(aParticipant(), fixedClock);
141
+
142
+ // Assert
143
+ assertThat(result.isFailure()).isTrue();
144
+ assertThat(result.error()).isEqualTo(CapacityExceededError.INSTANCE);
145
+ }
146
+
147
+ @Test
148
+ void should_emit_domain_event_when_registration_succeeds() {
149
+
150
+ // Arrange
151
+ var event = EventBuilder.anEventWithCapacity(10).build();
152
+
153
+ // Act
154
+ var result = event.register(aParticipant(), fixedClock);
155
+
156
+ // Assert
157
+ assertThat(result.isSuccess()).isTrue();
158
+ assertThat(result.domainEvents()).hasSize(1)
159
+ .first()
160
+ .isInstanceOf(ParticipantRegisteredEvent.class);
161
+ }
162
+ }
163
+ ```
164
+
165
+ The exact `Result` API is implementation-specific and MUST follow the application's established
166
+ Result model.
167
+
168
+ ---
169
+
170
+ ## 5. Application Service / Use Case Unit Tests
171
+
172
+ ### Rules
173
+
174
+ * No Spring context unless the behaviour being tested specifically requires framework wiring.
175
+ * Use JUnit 5 and Mockito where mocking output ports is appropriate.
176
+ * Mock output ports such as persistence, messaging, external service, and event publication ports.
177
+ * Do NOT mock domain objects.
178
+ * Test orchestration logic only.
179
+ * Do NOT re-test domain invariants here.
180
+ * Tests MUST exercise the use case through its public application-facing contract.
181
+ * Application tests MUST verify the established application Result semantics where Result Mapping
182
+ is the standard failure mechanism.
183
+
184
+ ### Mandatory Scenarios per Handler
185
+
186
+ Every Command Handler and Query Handler SHOULD have tests covering applicable scenarios:
187
+
188
+ | Scenario | Assertion |
189
+ | ---------------------- | ------------------------------------------------------------------------- |
190
+ | ✅ Happy path | Correct output port called; correct successful Result returned |
191
+ | ❌ Validation failure | Correct failed Result or established application error behaviour returned |
192
+ | ❌ Not found | Correct failed Result or established application error behaviour returned |
193
+ | ⚡ Concurrency conflict | Correct concurrency failure Result/error behaviour returned |
194
+ | ❌ Dependency failure | Correct failure behaviour returned without corrupting application state |
195
+
196
+ The test MUST NOT require a specific exception type when the established application Result model
197
+ represents that failure explicitly.
198
+
199
+ ### Port Argument Verification
200
+
201
+ Use `@Captor` to assert the exact argument passed to output ports where the argument itself is
202
+ important to the use-case behaviour.
203
+
204
+ ```java
205
+ @Captor
206
+ ArgumentCaptor<Registration> registrationCaptor;
207
+
208
+ verify(saveRegistrationPort).save(registrationCaptor.capture());
209
+
210
+ assertThat(registrationCaptor.getValue().status())
211
+ .isEqualTo(RegistrationStatus.CONFIRMED);
212
+ ```
213
+
214
+ ---
215
+
216
+ ## 6. Controller / Primary Adapter Slice Tests
217
+
218
+ ### Rules
219
+
220
+ * Use `@WebMvcTest(XxxController.class)` where Spring MVC slice testing is appropriate.
221
+ * Mock the application input/use-case port.
222
+ * Do NOT load the full application context for ordinary controller slice tests.
223
+ * Do NOT test business logic — that belongs in application/domain tests.
224
+ * Tests exercise only the public HTTP surface.
225
+ * HTTP error responses MUST follow the application's Problem Details standard.
226
+
227
+ ### Mandatory Scenarios per Endpoint
228
+
229
+ | Scenario | Assertion |
230
+ | -------------------------- | -------------------------------------------------------------------- |
231
+ | ✅ Happy path | Correct HTTP status (200/201/204) and response body shape |
232
+ | ❌ Invalid request body | HTTP 400 with standardized validation/Problem Details representation |
233
+ | 🔒 Unauthenticated | HTTP 401 where authentication is required |
234
+ | 🔒 Insufficient permission | HTTP 403 where authorization is required |
235
+ | ❌ Resource not found | Standardized HTTP 404 Problem Details response |
236
+ | ❌ Application failure | Appropriate HTTP status and Problem Details representation |
237
+ | ⚡ Concurrency conflict | Standardized HTTP 409 response where applicable |
238
+
239
+ Controller tests MUST NOT duplicate the internal logic of Result Mapping or Problem Details.
240
+
241
+ ---
242
+
243
+ ## 7. Persistence / Secondary Adapter Integration Tests
244
+
245
+ ### Rules
246
+
247
+ * Use `@DataJpaTest` with Testcontainers PostgreSQL where persistence integration behaviour is
248
+ being tested.
249
+ * `@AutoConfigureTestDatabase(replace = NONE)` SHOULD be used when required to prevent replacement
250
+ with an embedded database.
251
+ * **Never use H2 or another in-memory substitute for PostgreSQL integration tests.**
252
+ * Testcontainers configuration MUST use an approved PostgreSQL version managed by the project.
253
+ * Flyway migrations MUST be applied before persistence integration tests where migrations are part
254
+ of the application's persistence configuration.
255
+ * Tests SHOULD validate the migrated schema rather than relying on Hibernate schema generation.
256
+
257
+ ### Mandatory Scenarios
258
+
259
+ Where applicable, persistence tests MUST verify:
260
+
261
+ * Entity mapping is correct.
262
+ * Column types, nullability, constraints, and indexes behave as expected.
263
+ * Repository adapter behaviour is correct.
264
+ * Specifications produce the expected query results.
265
+ * Pagination and ordering behave correctly.
266
+ * Optimistic concurrency behaviour is correctly persisted and detected.
267
+ * Soft-delete restrictions behave correctly.
268
+ * Flyway migrations apply cleanly from a blank schema.
269
+ * Unique and other database constraints produce the expected persistence failure behaviour.
270
+
271
+ Custom JPQL or native queries SHOULD only be tested where such queries are explicitly required by
272
+ the persistence design.
273
+
274
+ ### Shared Base Class Pattern
275
+
276
+ ```java
277
+ @Testcontainers
278
+ public abstract class AbstractPersistenceTest {
279
+
280
+ @Container
281
+ static final PostgreSQLContainer<?> POSTGRES =
282
+ new PostgreSQLContainer<>("postgres:<approved-version>")
283
+ .withDatabaseName("app_test")
284
+ .withUsername("app_test")
285
+ .withPassword("app_test");
286
+
287
+ @DynamicPropertySource
288
+ static void configureDataSource(DynamicPropertyRegistry registry) {
289
+
290
+ registry.add("spring.datasource.url", POSTGRES::getJdbcUrl);
291
+ registry.add("spring.datasource.username", POSTGRES::getUsername);
292
+ registry.add("spring.datasource.password", POSTGRES::getPassword);
293
+ }
294
+ }
295
+ ```
296
+
297
+ The PostgreSQL version MUST be supplied through the project's dependency/version-management policy
298
+ rather than being prescribed by this rule.
299
+
300
+ ---
301
+
302
+ ## 8. Full Integration Tests
303
+
304
+ ### Rules
305
+
306
+ * Use `@SpringBootTest(webEnvironment = RANDOM_PORT)` + Testcontainers.
307
+ * Use `WebTestClient` or `RestAssured` for HTTP calls against the running application.
308
+ * Reserve full integration tests for **critical end-to-end flows** only.
309
+ * Full integration tests are not a substitute for unit or slice tests.
310
+ * Keep the total count intentionally small to protect CI execution time.
311
+
312
+ ### Candidate Flows
313
+
314
+ * Core happy-path user journey.
315
+ * Authentication and authorization flow.
316
+ * Cross-module application-event flow.
317
+ * Critical persistence transaction flow.
318
+ * Critical error-response flow involving Result Mapping and Problem Details.
319
+
320
+ ---
321
+
322
+ ## 9. Architecture Tests (ArchUnit)
323
+
324
+ Architecture tests run on every build and enforce Hexagonal Architecture and module boundaries.
325
+
326
+ ### Mandatory Rules
327
+
328
+ ```java
329
+ @AnalyzeClasses(packages = "com.yourproject")
330
+ class HexagonalArchitectureTest {
331
+
332
+ @ArchTest
333
+ ArchRule domainIsFrameworkFree =
334
+ noClasses()
335
+ .that().resideInAPackage("..domain..")
336
+ .should().dependOnClassesThat()
337
+ .resideInAnyPackage(
338
+ "org.springframework..",
339
+ "jakarta.persistence..",
340
+ "javax.persistence.."
341
+ );
342
+
343
+ @ArchTest
344
+ ArchRule applicationDoesNotDependOnAdapters =
345
+ noClasses()
346
+ .that().resideInAPackage("..application..")
347
+ .should().dependOnClassesThat()
348
+ .resideInAPackage("..adapter..");
349
+
350
+ @ArchTest
351
+ ArchRule noDirectCrossModuleDomainImports =
352
+ noClasses()
353
+ .that().resideInAPackage("..moduleA..")
354
+ .should().dependOnClassesThat()
355
+ .resideInAPackage("..moduleB..domain..");
356
+
357
+ @ArchTest
358
+ ArchRule portsMustBeInterfaces =
359
+ classes()
360
+ .that().haveNameMatching(".*Port")
361
+ .should().beInterfaces();
362
+ }
363
+ ```
364
+
365
+ Architecture tests SHOULD additionally verify that:
366
+
367
+ * Domain does not depend on HTTP or Problem Details types.
368
+ * Domain does not depend on Logging or logging implementations.
369
+ * Application does not depend directly on infrastructure adapters.
370
+ * Modules do not access another module's repositories or domain internals.
371
+ * Result Mapping and Problem Details remain at the HTTP/infrastructure boundary.
372
+
373
+ ---
374
+
375
+ ## 10. Result Mapping and Problem Details Tests
376
+
377
+ Because Result Mapping and Problem Details are explicit technical capabilities, their reusable
378
+ implementations MUST have focused tests.
379
+
380
+ ### Result Mapping
381
+
382
+ Tests SHOULD verify:
383
+
384
+ * Successful generic Result → successful HTTP response containing the Result value.
385
+ * Successful non-generic Result → successful HTTP response without a body.
386
+ * Failed Result → delegation to Problem Details.
387
+ * Result Mapping does not construct a second/custom Problem Details representation.
388
+ * Result Mapping does not bypass the established Problem Details mechanism.
389
+
390
+ ### Problem Details
391
+
392
+ Tests SHOULD verify:
393
+
394
+ * Standard Problem Details fields are populated correctly.
395
+ * Application errors can be represented as Problem Details.
396
+ * Appropriate exceptions can be mapped.
397
+ * Validation errors can be represented without performing validation.
398
+ * Diagnostic metadata is included only when configured and available.
399
+ * Sensitive exception information is not exposed.
400
+ * Stack traces are disabled by default for production configuration.
401
+
402
+ These tests MUST NOT move Problem Details or HTTP-specific types into Domain or Application tests.
403
+
404
+ ---
405
+
406
+ ## 11. Test Data and Fixtures
407
+
408
+ ### Rules
409
+
410
+ * Use a **shared fixture/builder library** per project where repeated fixtures provide value.
411
+ * Builders use the Builder pattern or static factory methods.
412
+ * Builders provide sensible defaults.
413
+ * Tests override only values relevant to the scenario.
414
+ * Domain-specific sentinel values belong in the project's domain testing rules.
415
+
416
+ ### Builder Pattern
417
+
418
+ ```java
419
+ public class RegistrationBuilder {
420
+
421
+ private ParticipantId participantId =
422
+ ParticipantId.of(
423
+ UUID.fromString("00000000-0000-0000-0000-000000000001")
424
+ );
425
+
426
+ private EventId eventId =
427
+ EventId.of(
428
+ UUID.fromString("00000000-0000-0000-0000-000000000002")
429
+ );
430
+
431
+ private RegistrationStatus status =
432
+ RegistrationStatus.CONFIRMED;
433
+
434
+ public static RegistrationBuilder aRegistration() {
435
+ return new RegistrationBuilder();
436
+ }
437
+
438
+ public RegistrationBuilder withStatus(RegistrationStatus status) {
439
+ this.status = status;
440
+ return this;
441
+ }
442
+
443
+ public Registration build() {
444
+ return Registration.reconstitute(
445
+ participantId,
446
+ eventId,
447
+ status
448
+ );
449
+ }
450
+ }
451
+ ```
452
+
453
+ ---
454
+
455
+ ## 12. Coverage Targets
456
+
457
+ | Layer | Target | Tool | CI Gate |
458
+ | ----------------------------------------------- | ------------------------------------ | ------ | ------------- |
459
+ | Domain — aggregate behaviours and value objects | **100%** line + branch | JaCoCo | ✅ Fails build |
460
+ | Domain — all other domain code | **85%** line | JaCoCo | ✅ Fails build |
461
+ | Application — use case handlers | **85%** line | JaCoCo | ✅ Fails build |
462
+ | Primary Adapters | No fixed target — slice-tested | — | — |
463
+ | Secondary Adapters | No fixed target — integration-tested | — | — |
464
+
465
+ Coverage MUST be considered together with test quality and meaningful assertions.
466
+
467
+ Coverage MUST be measured on the changed-files delta per PR in addition to overall package
468
+ thresholds where supported by the CI tooling.
469
+
470
+ A PR that drops overall coverage below the approved threshold MUST be rejected by CI.
471
+
472
+ ---
473
+
474
+ ## 13. CI Pipeline Test Gates
475
+
476
+ All of the following MUST pass before a PR can merge to `main`:
477
+
478
+ | Gate | Failure Action |
479
+ | -------------------------------------------------------- | -------------- |
480
+ | All unit tests pass | ❌ Block merge |
481
+ | All integration tests pass | ❌ Block merge |
482
+ | All ArchUnit architecture tests pass | ❌ Block merge |
483
+ | Domain + Application layer coverage ≥ approved threshold | ❌ Block merge |
484
+ | Required aggregate/value-object coverage achieved | ❌ Block merge |
485
+ | Test count report published | Informational |
486
+
487
+ Integration test execution time SHOULD be monitored and optimized where necessary.
488
+
489
+ ### Security Hygiene in CI
490
+
491
+ * Test credentials MUST use non-production placeholder values.
492
+ * Integration tests MUST NOT use production environment variables.
493
+ * Tests MUST never hit production endpoints or production databases.
494
+ * Testcontainers MUST use isolated test infrastructure.
495
+ * Sensitive test data MUST NOT be committed to source control.
496
+
497
+ ---
498
+
499
+ ## 14. Test-First Workflow
500
+
501
+ ```text
502
+ 1. Write the failing test → confirm it fails (RED)
503
+
504
+ 2. Write minimum production code → confirm it passes (GREEN)
505
+
506
+ 3. Refactor → confirm tests still pass (REFACTOR)
507
+
508
+ 4. Commit test + production code together
509
+ ```
510
+
511
+ This workflow is **non-negotiable**.
512
+
513
+ A PR that adds production behaviour without appropriate accompanying tests MUST be rejected during
514
+ code review, unless the change is explicitly classified as a non-behavioural configuration,
515
+ documentation, or infrastructure-only change where tests are not applicable.
516
+
517
+ ---
518
+
519
+ ## 15. Frontend Test Stack (if applicable)
520
+
521
+ Frontend testing is governed by the frontend/UI lane where one is present.
522
+
523
+ | Test Type | Framework | Scope |
524
+ | ---------------------- | -------------------------------------------- | --------------------------------- |
525
+ | Component unit | Project-approved frontend test framework | Rendering, user interactions |
526
+ | Hook / composable unit | Project-approved frontend test framework | Custom hooks and state logic |
527
+ | API client unit | Project-approved frontend test framework | Request format and error handling |
528
+ | E2E | Playwright or project-approved E2E framework | Critical user journeys |
529
+
530
+ Frontend-specific coverage targets SHOULD be defined by the frontend lane rather than this
531
+ backend technology rule.
532
+
533
+ ---
534
+
535
+ ## 16. Required Dependencies
536
+
537
+ The exact versions MUST be controlled by the project's centralized dependency management or
538
+ approved BOM.
539
+
540
+ Typical testing dependencies include:
541
+
542
+ ```xml
543
+ <!-- Testing stack -->
544
+ <dependency>
545
+ <groupId>org.springframework.boot</groupId>
546
+ <artifactId>spring-boot-starter-test</artifactId>
547
+ <scope>test</scope>
548
+ </dependency>
549
+
550
+ <dependency>
551
+ <groupId>org.testcontainers</groupId>
552
+ <artifactId>postgresql</artifactId>
553
+ <scope>test</scope>
554
+ </dependency>
555
+
556
+ <dependency>
557
+ <groupId>org.testcontainers</groupId>
558
+ <artifactId>junit-jupiter</artifactId>
559
+ <scope>test</scope>
560
+ </dependency>
561
+
562
+ <dependency>
563
+ <groupId>com.tngtech.archunit</groupId>
564
+ <artifactId>archunit-junit5</artifactId>
565
+ <scope>test</scope>
566
+ </dependency>
567
+ ```
568
+
569
+ The project MAY use additional testing libraries where justified. This rule MUST NOT hardcode
570
+ library versions.
571
+
572
+ ---
573
+
574
+ ## 17. Risks and Mitigations
575
+
576
+ | Risk | Mitigation |
577
+ | ------------------------------------------ | --------------------------------------------------------------------------------------------------- |
578
+ | Slow integration tests blocking CI | Share Testcontainers infrastructure where appropriate; reserve `@SpringBootTest` for critical flows |
579
+ | Coverage gamed by trivial tests | Code review policy requires meaningful assertions and behaviour-focused tests |
580
+ | Testcontainers unavailable in CI | CI runners MUST provide supported container execution |
581
+ | Non-deterministic test failures | Inject `Clock` and identity generation where required |
582
+ | Cross-module coupling introduced silently | ArchUnit cross-module boundary rules fail the build |
583
+ | Tests written after production code | PR review requires tests for applicable behavioural changes |
584
+ | Error behaviour diverges from API standard | Controller and Problem Details integration tests verify standardized error responses |
585
+ | Result Mapping duplicates error handling | Focused Result Mapping tests verify delegation to Problem Details |
586
+
587
+ ```
588
+
589
+ ### One important point
590
+
591
+ I would **not change the testing file beyond this level**. In particular, I would not add detailed package structures, exact Spring annotations, or exact class names because your other guardrails correctly state that implementation details should remain configurable.
592
+
593
+ Also, your **`technology-constitution.md` itself has one inconsistency** that should eventually be corrected:
594
+
595
+ > Principle X says: **"Structured logging using SLF4J/Logback"**
596
+
597
+ But `logging.md` says the **backend/provider is pluggable** and only SLF4J is the default API/facade. Therefore the constitution should say something like:
598
+
599
+ > **Structured logging using the approved SLF4J API/facade and configured approved implementation; provider substitution must remain possible.**
600
+
601
+ That is a **separate small change** I recommend making to `technology-constitution.md`.