pytest basics: assertions, test files, and discovery rules
Informational article in the Testing Python Projects with pytest topical map — Getting started with pytest content group. 12 copy-paste AI prompts for ChatGPT, Claude & Gemini covering SEO outline, body writing, meta tags, internal links, and Twitter/X & LinkedIn posts.
pytest basics: assertions, test files, and discovery rules: pytest discovers tests by default by collecting functions named test_* and test classes named Test* from files that match the two filename patterns test_*.py and *_test.py, recursively under the current directory and its subdirectories. This behavior follows pytest's default collection rules and will import test modules to inspect for callables; test discovery will skip directories named with a leading dot or those excluded via pytest.ini patterns. The filename patterns are the single most important factor to ensure runnable tests in both local environments and CI. Test modules are imported with standard Python import semantics, so package layout and sys.path affect discovery.
Collection uses a mix of import-time introspection and AST-level analysis plus pytest's assert rewriting to produce rich failure diffs and local variable values, which distinguishes pytest from unittest and plain assert statements. Tools such as tox and CI runners invoke pytest's collector, which applies pytest naming conventions and discovery patterns from pytest.ini, pytest.conf, or pyproject.toml to include or ignore paths. The test collector looks for functions, methods, and classes, then creates nodes that are executed by the runner; fixtures declared in conftest.py provide dependency injection across collected tests. Command-line flags like -k for substring selection and -q for quieter output alter what the collector runs without changing file layout. Plugins such as pytest-xdist or coverage integrate at collection and runtime.
A frequent misconception is that plain Python assert yields the same output across runners; in reality pytest's assert rewriting transforms assert expressions at import time so failures include evaluated operands and inline diffs, unlike unittest's self.assertEqual style, which explains why raw assert formatting may look sparse outside pytest. Another common pitfall is incorrect naming: files like testsinstead.py or classes named TestMath without test_ prefixed functions will not be collected, breaking pytest test discovery. Misplacing conftest.py in the wrong package root can hide fixtures from subpackages in CI, causing inexplicable fixture lookup errors. Correct adherence to pytest test files naming and conftest.py fixtures placement prevents most discovery-related failures. Selection flags like -k can hide absent tests during collection and thus obscure true collection results.
Practical steps include naming test files using the test_*.py or *_test.py patterns, writing test functions named test_* or methods in classes named Test*, relying on pytest assertions so assert rewriting yields informative diffs, and placing shared fixtures in conftest.py at the repository root or package root so CI sees them. Running pytest with -q and using -k expressions helps narrow runs during development while preserving discovery rules for CI. The rest of this page provides a structured, step-by-step framework for writing pytest tests, arranging pytest test files, and configuring discovery rules for reliable local and CI execution.
- Work through prompts in order — each builds on the last.
- Click any prompt card to expand it, then click Copy Prompt.
- Paste into Claude, ChatGPT, or any AI chat. No editing needed.
- For prompts marked "paste prior output", paste the AI response from the previous step first.
how does pytest discover tests
pytest basics: assertions, test files, and discovery rules
authoritative, conversational, practical
Getting started with pytest
Python developers (beginner to intermediate) who want a compact, actionable guide to writing assertions, organizing test files, and understanding pytest discovery so tests run reliably in local and CI environments
A tightly-focused 1,000-word practical guide that distills the three most common pytest entry barriers—assertions, test file structure, and discovery rules—into copy/paste examples, config snippets, common pitfalls and quick fixes, so readers can get reproducible tests fast.
- pytest assertions
- pytest test discovery
- pytest test files
- writing pytest tests
- assert statement vs pytest assert
- conftest.py fixtures
- pytest naming conventions
- pytest discovery patterns
- pytest -k -q flags
- Using bare Python assert formatting without showing pytest's introspection benefits, leaving beginners confused why failures show rich diffs.
- Naming test files/functions incorrectly (e.g., testsinstead.py or TestMath instead of tests/test_math.py and test_* functions) which prevents discovery.
- Placing conftest.py in the wrong directory causing fixtures not to be discovered in subpackages or CI runs.
- Assuming pytest will run modules that aren’t importable from the project root — missing __init__.py or wrong PYTHONPATH leads to import errors.
- Not documenting the pytest version and CLI flags used, causing reproducibility problems between local and CI environments.
- Overloading assertions with complex logic instead of small, single-assert tests that give clearer failure signals.
- Relying on relative imports in test files that work locally but fail in CI due to different working directories.
- Always show one-line pytest commands in examples (pytest -q and pytest tests/test_math.py::test_add) — readers copy them directly into terminals.
- Include a minimal conftest.py with a fixture example and explain the discovery rule: conftest applies to subdirectories; place it at test package root.
- For CI tips, recommend pinning pytest version and running pytest --maxfail=1 --disable-warnings to get fast, noisy failures during builds.
- When showing assertions, include an example with multiple comparisons and note pytest's enhanced assertion rewriting so readers don't need assertEqual.
- Add an explicit 'How to debug discovery' checklist: run pytest -vv, check naming, run python -c 'import sys; print(sys.path)' in CI step, and ensure tests run from project root.
- Provide both file-based and module-based examples (tests/test_math.py and package/tests/test_math.py) to address different repo layouts.
- Mention the common migration pitfall from unittest: avoid mixing unittest.TestCase methods with pytest-style asserts unless necessary, and show the equivalent pytest pattern.