5.6 KiB
name, description, argument-hint
| name | description | argument-hint |
|---|---|---|
| pytest-scaffolding | Scaffold a maintainable, hierarchical pytest suite for core functionality first, then extend safely. Use when setting up tests, organizing fixtures by dependency, mirroring src structure in tests, or enforcing fast-by-default test runs. | Target scope (for example: app/services/job, app/ai, or full repo) |
Pytest Scaffolding
Create test scaffolding that is:
- Hierarchical: test layout roughly mirrors source layout.
- Fast by default: most tests run in under a second total for core units.
- Dependency-aware: slow/external dependencies are isolated behind markers and fixture scope.
- Extensible: minimal initial skeleton supports adding detailed tests later without refactors.
This repository currently uses:
uv run pytestas the canonical test invocation.pyproject.tomlpytest config under[tool.pytest.ini_options].- strict marker checking (
--strict-markers).
Load pytest references when you need detailed rules.
When To Use
- Bootstrapping tests for a new or existing Python repo.
- Reorganizing tests that have become flat, slow, or difficult to extend.
- Defining fixture boundaries before writing many assertions.
- Creating only the first-layer scaffold for core behavior (not exhaustive coverage yet).
Inputs To Collect
- Target test scope: full repo, package, or module.
- Dependency profile: pure Python, DB, network/API, filesystem, UI/browser.
- Runtime expectation: what must be instant vs allowed to be slower.
- CI policy: which marker groups must block merges.
If these are missing, ask concise clarifying questions before editing.
Workflow
- Map source tree to test tree.
- Classify tests by dependency cost.
- Create minimal directories and placeholder test modules.
- Create fixture layers (
tests/conftest.pyplus localconftest.pyin subtrees only when needed). - Register markers and default selection behavior.
- Run collection and fast path tests.
- Report gaps and next extension points.
Step 1: Map Source To Tests
Create a mirrored structure rooted at tests/ that follows major source concepts.
Example mapping pattern:
src/app/services/job.py->tests/app/services/test_job.pysrc/app/ai/graphs/transcription.py->tests/app/ai/graphs/test_transcription.pysrc/app/api/routes.py->tests/app/api/test_routes.py
Rules:
- One initial test module per core source module.
- Prefer
test_<module>.pynaming. - Keep directory mirrors shallow first; add deeper modules only where behavior is complex.
Step 2: Classify By Dependency Cost
Assign each test module to one initial class:
unit: no DB/network/filesystem side effects; instant execution.integration: touches DB, HTTP stack, workflow runtime, or external services.smoke: thin end-to-end confidence checks.
Decision logic:
- If logic can run with fakes/stubs, make it
unit. - If contract with framework/DB is essential, make it
integration. - If validating a user-critical path across layers, make it
smoke.
Step 3: Scaffold Minimal Test Modules
For each target module, scaffold:
- import section
- one happy-path test function
- one error/edge test function
- TODO comments indicating detail expansion points
Keep assertions minimal but behavior-focused. Avoid large fixtures in module files.
Step 4: Fixture Layering Strategy
Use fixture scopes based on cost:
functionscope by default.- broader scopes (
module/session) only for expensive setup with clear teardown.
Layer fixtures by directory:
tests/conftest.py: global, lightweight fixtures only (factories, deterministic defaults).- subtree
conftest.py: domain-specific fixtures (API client, DB session, AI runtime stubs).
Guidelines:
- Prefer yield fixtures for setup/teardown.
- Keep fixtures atomic (one state-changing responsibility per fixture).
- Avoid autouse except for truly universal behavior.
Step 5: Marker Taxonomy And Config
Ensure marker names are explicit and registered in pyproject.toml because strict markers are enabled.
Recommended baseline markers:
unitintegrationsmokeslowexternal(requires network/service credentials)
Default run strategy:
- Fast local path: run only
unitby default in day-to-day iteration. - Full validation path: run all markers in CI or pre-release checks.
Step 6: Execution And Verification
Run commands in this order:
uv run pytest --collect-only -quv run pytest -m unit -quv run pytest -q(if dependencies are available)
Optional targeted runs:
- by node id for one test
- by
-kexpression for focused iteration
Step 7: Completion Checks
A scaffold pass is complete when all are true:
- Every core source area has at least one corresponding test module.
- Unit tests run quickly and deterministically.
- Integration/external tests are isolated by marker and fixture boundaries.
- No unregistered marker warnings/errors.
tests/structure is understandable without extra documentation.- A clear TODO path exists for deepening assertions later.
Branching Scenarios
- If external APIs are required: provide stubs/mocks for unit tests; guard real calls behind
externalmarker. - If DB is required: build a dedicated integration fixture layer and keep unit tests DB-free.
- If tests become slow: split slow tests via marker and widen fixture scope only where safe.
- If naming conflicts appear: keep unique test module names or package test directories explicitly.
Output Format
When applying this skill, provide:
- Proposed test tree diff.
- Marker and fixture plan.
- Exact commands for fast path and full path.
- Risks/open questions before writing detailed assertions.