pytest-cases
Separate test code from test cases in pytest, with fixture unions and parametrization goodies for readable, reusable test suites.
Repository Health
Technical Analysis
pytest-cases extends pytest’s @pytest.mark.parametrize model so that test cases can live independently from test functions. Instead of cramming inline parameter lists into a test file, you write case functions (or case classes) in a companion module, and decorate your test with @parametrize_with_cases to have pytest-cases collect, generate, and feed them into your test automatically, complete with readable auto-generated test IDs.
Beyond case separation, the library rewrites core pieces of pytest’s fixture machinery to support “fixture unions” — the ability to use a fixture reference as a parameter value and let a single test run across several alternative fixtures without duplicating test code. It also ships lazy_value for deferred parameter computation, @fixture as a drop-in @pytest.fixture replacement with extra powers, and tight interoperability with pytest-harvest for benchmark-style result collection. The result is a small, focused toolkit for teams whose test suites have outgrown plain parametrize but don’t want to hand-roll fixture composition themselves.
What You Get
@parametrize_with_casesdecorator that discovers case functions/classes in a companion module and feeds them into a test, with automatic readable test IDs@fixtureand@parametrizedrop-in replacements for@pytest.fixture/@pytest.mark.parametrizewith extended capabilities (union support, lazy values, ids)fixture_unionandfixture_refto let a test consume one of several alternative fixtures without duplicating the test bodylazy_valuefor parameter values that are computed only when a specific test case actually runs, instead of at collection time- Case tagging and filtering (
@case(tags=...),matches_tag_query) to select subsets of cases to run get_current_cases/current_casesfixture to introspect which case produced the current test’s parameters, useful for benchmark-style reporting with pytest-harvest
Common Use Cases
- Moving large, hand-maintained
@pytest.mark.parametrizeargument lists out of test files and into dedicated, documented case modules - Testing a function against many structurally different inputs (dataframes, files, generated data) where each case needs its own setup code
- Running the same test body against several interchangeable fixtures (e.g. different backends or drivers) via fixture unions instead of copy-pasted tests
- Building small data-science or ML benchmarks that compare several models/datasets, combined with pytest-harvest to collect timing and results
- Sharing a library of reusable case functions across multiple test files or even multiple projects
Under The Hood
Architecture
The package is organized as a set of composable pytest internals extensions rather than a single monolithic plugin: case_parametrizer_new.py implements case discovery and the @parametrize_with_cases decorator, fixture_core1_unions.py and fixture_core2.py implement fixture unions and the extended @fixture decorator, and fixture_parametrize_plus.py implements the extended @parametrize/fixture_ref mechanism, with plugin.py wiring these into pytest’s hook system (via pytest_generate_tests-style hooks) so behavior activates automatically once the package is installed. This layered structure means the case-discovery layer and the fixture-union layer can be reasoned about mostly independently, even though both ultimately reach into pytest’s private CallSpec2/collection internals to inject their extended parametrization logic.
Tech Stack
Written in pure Python with no runtime dependencies beyond pytest itself, plus decopatch and makefun for building well-signatured decorators, and packaging for version comparisons. The project targets Python 3.9 through 3.14 and pytest 6 through 9, using setuptools with setuptools_scm for git-tag-based versioning and nox to run the test matrix across supported interpreter/pytest combinations.
Code Quality
The repository ships an extensive test suite (193 test files under tests/) covering case discovery, fixture unions, parametrization edge cases, and a dedicated pytest_extension suite that exercises the plugin against pytest’s own test harness. CI runs the full nox matrix across Python and pytest versions on GitHub Actions, with flake8 linting (max line length 120, custom copyright-header check) and generated coverage/JUnit reports published to GitHub Pages. Code favors defensive compatibility shims (try/except ImportError fallbacks for cross-version pytest internals) over strict typing, reflecting its role as a plugin that must track multiple pytest major versions simultaneously.
What Makes It Unique
Most pytest parametrization helpers only add convenience on top of @pytest.mark.parametrize; pytest-cases instead reaches into pytest’s fixture resolution engine to support genuine “fixture unions” — parametrizing a test across a set of fixtures rather than plain values, something pytest has no native mechanism for. Combined with lazy-evaluated parameter values and case discovery across files or classes, it turns test-case management into a first-class, reusable abstraction rather than an ad hoc collection of parametrize lists.
Used by 2 apps in this directory
Qdrant
Databases · AI Development · Search
Open-source vector database and search engine built in Rust for production-grade AI applications — from semantic search to RAG pipelines and recommendation systems.
Timeplus Proton
Data Engineering · Analytics
Single C++ binary SQL engine for real-time stream processing, ETL, and analytics on Kafka, Redpanda, and ClickHouse with sub-millisecond latency.