$npx -y skills add maksimzayats/specx --skill specx-testsAdd or refine tests for specx Python services. Use when creating unit tests for use cases/services, integration tests for FastAPI controllers or infrastructure adapters, e2e smoke tests, architecture import guardrails, DI override tests, pytest fixtures, or coverage and boundary
| 1 | # specx Tests |
| 2 | |
| 3 | Use this skill when behavior, wiring, or architecture boundaries need tests. |
| 4 | Read `references/testing.md` before creating test files. |
| 5 | |
| 6 | ## Test Layers |
| 7 | |
| 8 | - `tests/_support/`: generic clients, DB helpers, and shared integration |
| 9 | helpers only. This is not a test suite and does not hold project-specific |
| 10 | doubles. |
| 11 | - `tests/unit/`: core services, use cases, and capabilities resolved from a |
| 12 | fresh application container returned by the project's `get_container()`. |
| 13 | - `tests/integration/`: real internal graph tests. Core use-case integration |
| 14 | tests call resolved use cases against the transactional DB; delivery |
| 15 | integration tests exercise HTTP mapping; migrations prove Alembic behavior. |
| 16 | - `tests/e2e/`: optional whole-app smoke flows. |
| 17 | - `tests/guardrails/`: optional programmatic |
| 18 | `specx.testing.architecture.assert_specx_architecture` wrappers for genuinely |
| 19 | project-specific extra rules. Standard packaged rules run through |
| 20 | `uv run specx check`. |
| 21 | |
| 22 | ## Rules |
| 23 | |
| 24 | - Test behavior and boundaries, not implementation ceremony. |
| 25 | - Required generated coverage is currently scoped to core services, use cases, |
| 26 | and capabilities. |
| 27 | - Mirror source module paths directly with flat test files, for example |
| 28 | `tests/unit/core/tasks/services/test_title_service.py`. |
| 29 | - Do not create per-target test folders, `harness.py`, target factories, or |
| 30 | target harnesses. |
| 31 | - `tests/unit/conftest.py` owns the fresh real-app `Container` fixture for unit |
| 32 | tests and any project-wide test overrides. `tests/integration/conftest.py` |
| 33 | owns the transactional DB-backed `container` fixture for integration tests. |
| 34 | - Test functions receive `container`, register any scenario-specific overrides |
| 35 | before resolution, then call `container.resolve(Target)`. |
| 36 | - If a complete replacement is needed by every test in one module, a |
| 37 | module-local `container` fixture may register it before returning the |
| 38 | container. |
| 39 | - Keep one-off class-based test doubles in the `test_*.py` module that uses |
| 40 | them. When the same double is reused by multiple unit modules, put it in a |
| 41 | mirrored |
| 42 | `tests/unit/core/<scope>/{capabilities,gateways,repositories}/fake_<source_module>.py` |
| 43 | file. |
| 44 | - Do not create `tests/_support/fakes`, `tests/**/_fakes.py`, generic |
| 45 | `_scenarios.py`, fake modules outside those mirrored unit port/capability |
| 46 | packages, or double classes in `conftest.py`. |
| 47 | - Use `MagicMock` or `AsyncMock` inline in the test function when only one |
| 48 | behavior needs to be changed for that scenario. Prefer autospeccing when |
| 49 | call signatures matter and `spec_set` when unexpected attributes must fail. |
| 50 | - Unit tests replace external IO, time, randomness, network, Redis, database, |
| 51 | and framework resources with local doubles or inline mocks. |
| 52 | - Integration tests use the real internal app graph. Do not mock internal use |
| 53 | cases, services, or capabilities; stub only external systems when needed. |
| 54 | - Add core use-case integration tests under `tests/integration/core/...` for |
| 55 | use cases that inject a UoW manager; delivery tests should own HTTP mapping, |
| 56 | not be the only persistence proof. |
| 57 | - Persistence integration tests use the production database family when |
| 58 | dialect behavior matters. A rollback harness may not replace isolated |
| 59 | commit-visible tests for locking, concurrency, isolation, or after-commit |
| 60 | behavior. |
| 61 | - Core health tests cover required-dependency readiness and any reusable probe |
| 62 | services and use cases. |
| 63 | Delivery probe tests cover `/healthz` and `/readyz` as operational endpoints, |
| 64 | not versioned business API routes. `/healthz` must prove a lightweight |
| 65 | process response only; `/readyz` must prove required infrastructure readiness, |
| 66 | including a real bounded DB check for SQLAlchemy services. |
| 67 | - Probe route tests assert `Cache-Control: no-store`, readiness failure returns |
| 68 | `503`, probe routes are excluded from OpenAPI, and legacy `/api/v1/health` is |
| 69 | absent when replacing old generated health endpoints. |
| 70 | - Unit-test logging configurators by overriding logging settings, |
| 71 | monkeypatching `logging.config.dictConfig`, and asserting the generated |
| 72 | stdlib config. Use `caplog` only when a log record is meaningful behavior. |
| 73 | - Unit-test FastAPI lifecycle managers by overriding closeable infrastructure |
| 74 | resources and asserting shutdown order. Route integration helpers must run |
| 75 | ASGI lifespan explicitly. |
| 76 | - Use `httpx2`, not legacy `httpx`, for generated HTTP client and ASGI transport |
| 77 | tests. Enter `LifespanManager`, then pass the yielded manager's `manager.app` |
| 78 | to `ASGITransport` so request scopes receive lifespan state. |
| 79 | - FastAPI route tests compare response status codes with `fastapi.status` |
| 80 | constants, not raw integer literals. |
| 81 | - Use `container.resolve |