5.0 KiB
name, description, argument-hint
| name | description | argument-hint |
|---|---|---|
| pytest-scaffolding | Scaffold a maintainable, hierarchical pytest suite with fast defaults and clear escalation paths for FastAPI and SQLAlchemy tests. Use when creating or reorganizing tests, defining fixture/marker boundaries, or making test strategy progressively discoverable. | Target scope plus stack details (pure Python, FastAPI, SQLAlchemy sync, SQLAlchemy async, or mixed) |
Pytest Scaffolding
Create test scaffolding that stays fast for daily work and scales safely as dependencies increase.
This skill is optimized for progressive discoverability:
- Start with the shortest path in this file.
- Load exactly one deeper reference only when a decision requires it.
- Continue only as far as needed for the current task.
Repository defaults:
uv run pytestis the canonical invocation.- pytest settings live in
pyproject.tomlunder[tool.pytest.ini_options]. - strict marker checking is expected (
--strict-markers).
Discovery Ladder
Level 0: Scope And Stack Triage (always)
Collect:
- Target scope (repo, package, module).
- Stack shape (pure Python, FastAPI, SQLAlchemy sync, SQLAlchemy async, or mixed).
- Speed target (what must stay instant).
- CI gate policy (which marker groups block merge).
If any are missing, ask concise clarifying questions before scaffolding.
Level 1: Core pytest scaffold (default)
Use this for all stacks first:
- Mirror
src/intotests/with one starter file per core module. - Classify test intent by cost:
unit: no DB/network/filesystem side effects.integration: framework, DB, or multi-layer contracts.smoke: thin critical-path checks.
- Scaffold each new module with:
- one happy-path test,
- one failure/edge test,
- TODO anchors for deeper assertions.
- Keep fixtures layered:
- global lightweight fixtures in
tests/conftest.py, - domain fixtures in subtree
conftest.pyonly when needed.
- global lightweight fixtures in
- Register markers early:
unit,integration,smoke,slow,external. - Validate in order:
uv run pytest --collect-only -quv run pytest -m unit -quv run pytest -qwhen dependencies are available.
Load next reference only if needed:
- Baseline details and rationale: pytest-docs.md
- Condensed quick path variant: [pytest-docs copy.md](./references/pytest-docs copy.md)
Level 2: FastAPI branch (only for HTTP/dependency/lifespan concerns)
Escalate here when testing API routes, dependency injection boundaries, or app lifespan behavior.
Apply these defaults:
- Prefer
TestClientwith syncdeftests for route behavior. - Use
AsyncClient+@pytest.mark.anyioonly when test logic must await other async work. - Prefer
app.dependency_overridesover patching internals. - Reset dependency overrides in teardown after every test/fixture.
- For startup/shutdown semantics:
- use
TestClientas context manager, or - use
LifespanManagerwith async client.
- use
Marker intent in FastAPI-heavy suites:
unit: service logic without HTTP/DB.integration: route + DI + DB contract checks.smoke: one request per critical user path.
Reference: fastapi-testing.md
Level 3: SQLAlchemy branch (only for DB transaction/session design)
Escalate here when session lifecycle, transaction isolation, or async ORM behavior matters.
Apply these defaults:
- Create engine once per test session.
- Open connection + outer transaction per test.
- Bind session with
join_transaction_mode="create_savepoint". - Allow code under test to call
commit()safely; rollback outer transaction at test end. - Keep unit tests DB-free; DB tests belong under
integration.
Async additions:
- use async fixtures and
@pytest.mark.anyio. - set
expire_on_commit=FalseforAsyncSession. - avoid implicit lazy IO; use eager loading (
selectinload) or explicit refresh.
SQLite in-memory with threaded test clients:
- use
StaticPoolwhen required by thread/connection sharing.
Reference: sqlalchemy-testing.md
Branching Logic Summary
- If pure logic can be faked cleanly, keep in
unit. - If framework/DB contract is the behavior under test, use
integration. - If external service credentials/network is required, gate behind
external. - If suite slows down, split by marker before broadening fixture scope.
- If async relationship access raises
MissingGreenlet, switch to eager loading strategy.
Completion Checks
A scaffold pass is complete when all are true:
- Core source areas map to clear test modules.
- Fast path (
-m unit) is deterministic and quick. - Integration and external paths are isolated by fixtures and markers.
- No unregistered-marker failures occur.
- Structure is understandable without extra oral context.
- Clear TODO extension points exist for deeper assertions.
Output Contract
When this skill is applied, return:
- Proposed test tree diff.
- Marker and fixture plan.
- Exact fast-path and full-path commands.
- Which reference level was loaded and why.
- Risks or open questions before expanding assertions.