4.7 KiB
4.7 KiB
Pytest Naming Conventions and Test Organization
!!! info "Primary sources" - Good integration practices - Changing standard (Python) test discovery - How to use fixtures - How to parametrize fixtures and test functions - Marker examples
Agent Quick Path
Use this when creating or reorganizing test modules so naming and hierarchy stay predictable.
- Mirror the product domain structure in
tests/so ownership is obvious. - Encode broad context in module and class names (
test_*.py,Test*). - Keep leaf test names short and behavior-focused (
test_*). - Use
class Test<Subject>:only for grouping related scenarios. - Place fixtures in the nearest
conftest.pyneeded by scope. - Separate expensive tests with markers first, directories second.
Naming Conventions
File and directory naming
- Use lowercase snake_case for test file names:
test_user_service.py. - Keep directories domain-oriented and stable over time:
tests/orders/,tests/billing/. - Prefer descriptive test names over internal ticket numbers or implementation details.
Test function naming
- Prefer hierarchical naming: put broad context in folder/module/class, and keep the function name focused on the final assertion.
- Keep pytest discovery prefixes intact:
- modules start with
test_ - classes start with
Test - functions start with
test_
- modules start with
- Start with user-visible behavior or contract, not private helper names.
Recommended pattern:
- module:
test_<subject>.py - class:
Test<Operation>orTest<Scenario> - function:
test_<expected_outcome>
Examples:
- Flat (still valid):
test_create_order_rejects_invalid_currency - Class-context:
TestOrder -> TestCreate -> test_rejects_invalid_currency - Module-context:
test_order.py -> TestCreate -> test_rejects_invalid_currency - Module + class context can similarly shorten:
test_token.py -> TestRefresh -> test_rotates_session_idtest_user_list.py -> TestListUsers -> test_returns_empty_for_new_tenant
Test class naming
- Use
class Test<SubjectOrScenario>:for scenario grouping and context reduction. - Keep class names noun-focused (
TestOrderService) rather than action-focused. - Avoid xUnit style setup inheritance when fixtures can express dependencies directly.
Hierarchy and Organization Patterns
Two patterns work well; choose one and apply it consistently.
Pattern A: Source-mirror hierarchy (default for product code ownership)
src/
app/
orders/service.py
billing/invoice.py
tests/
app/
orders/test_service.py
billing/test_invoice.py
Use this when teams own modules by source path and want direct test-to-source mapping.
Pattern B: Cost-lane hierarchy (default for CI policy clarity)
tests/
unit/
orders/test_service.py
integration/
api/test_orders.py
persistence/test_order_repository.py
smoke/
test_health.py
Use this when CI gating is based on cost lanes and marker filtering.
Hybrid rule (recommended)
- Keep a source-mirror tree for local ownership.
- Add markers (
unit,integration,smoke,external) for runtime policy. - Avoid duplicating both trees unless the repository already requires it.
Fixture Placement Strategy
- Put universal lightweight fixtures in
tests/conftest.py. - Put domain fixtures in subtree
conftest.pyfiles close to where they are used. - Keep fixtures composable and explicit; avoid large fixture "god objects".
- Use
yieldfixtures for teardown so cleanup is always paired with setup.
Parametrize and ID Naming
- Use
pytest.mark.parametrizefor behavior matrices instead of copy/paste tests. - Provide explicit
ids=labels when case names are not obvious. - Keep IDs business-meaningful (
"expired-token","zero-balance") so failures are readable.
Collection and Structure Checks
Use these checks after introducing new test files or renaming modules:
uv run pytest --collect-only -quv run pytest -m unit -quv run pytest -m "not external" -q
If collection surprises appear, verify file names, marker registration, and directory placement first.
Common Anti-Patterns
- Mixed naming styles (
testFoo.py,test_foo.py,foo_test.py) in one repository. - Deep fixture chains that hide setup behavior.
- Test names that encode implementation details instead of behavior.
- Moving slow tests into
unitdirectories without marker updates. - Sharing mutable module-level state across tests.