pytest-airflow-in-a-box
Your Dag files import. Your task callables pass. Production still breaks.
Well, you never really verified the
DAG
Trigger rules, branch skips, rendered templates, connection resolution, and operator
serialization remain untested until deployment. This plugin runs those seams in pytest, in
your repo's own CI, with no scheduler, webserver, or ~/airflow.
For a team owning a dags/ repo on Airflow 3 that writes its own operators, hooks,
sensors, and connection types -- deployed by someone else (MWAA, Composer, Astro,
self-hosted). If your repo is 100% stock operators, dag.test() plus a DagBag import
test is enough; the full list is on the
documentation site.
Already have a DagBag import test and a pile of task.function(...) calls? Here is
exactly where they stop,
and why not dag.test(), DebugExecutor, or your own conftest.py.
Quickstart
def test_my_dag(dag_bag, run_dag):
dag = dag_bag.dags["my_dag_id"]
result = run_dag(dag)
assert result.success
assert result.order == ["extract", "load"]
pytest --dag-folder=dags
run_dag proves your real file, under its real dag_id, actually finishes in the states
you expect. dag_bag parses the folder once per worker process, and result.order records
execution order rather than graph topology. In-test Dags (dag_maker), single operators
without a database (run_task), and matchers are in the
Quickstart.
Installation
uv add --dev "pytest-airflow-in-a-box[airflow3]"
The plugin does not depend on Airflow directly: the Airflow 2.x monolith and the 3.x core both
install under the name apache-airflow, so a hard plugin pin would corrupt whichever family you did not
choose. The airflow3 extra pins apache-airflow>=3.1,<4, matching the dependency restriction
in pyproject.toml. Projects that already pin Airflow themselves -- for example through
Airflow's published constraints files -- install the plugin bare. Every extra and common
combination is listed under
Dependencies and extras.
In CI, nredd/pytest-airflow-in-a-box/action@v0 provisions a constraints-pinned environment --
see The GitHub Action.
Requirements
- CPython 3.10 through 3.14, pytest 8 or newer
- Apache Airflow 3.1 or newer, below 4; or a certified Airflow 2 release from 2.7 through 2.11
- Linux or macOS. Airflow has no native Windows support -- use WSL2 or the devcontainer
Which Airflow and Python combinations are actually exercised in CI, and what the 2.x tier does
and does not cover, are stated once in
Compatibility and certification.
After installing, pytest --airflow-doctor tells you whether your own pin works.
What ships
Typed fixtures, grouped by the job:
| Job | Reach for |
|---|---|
| Run one operator with no database | run_task, render_task, task_context |
Run a real DagRun and assert on it |
dag_maker, run_dag, dag_bag |
| Give the run its environment | airflow_home, airflow_configure, airflow_variables, airflow_connections |
| Register a custom component for one test | airflow_components |
| Assert on what a task logged | cap_structlog |
| Check every Dag at once | dag_corpus |
| Talk to a live Airflow API | api_client, api_base_url |
Every fixture, its return type, and its scope: Fixtures. Markers are listed in Markers.
Also in the box: corpus smoke checks (--airflow-smoke), a disposable metadata database, an
isolated AIRFLOW_HOME, report artifacts that survive -n auto, a
GitHub Action, and an
Airflow 2-to-3 migration toolkit fronted by the airflow-migration-diff console script.
Documentation
The documentation site follows the reader, one deep link per stage:
- Whose fail is it anyway? -- what earns a test
- The fidelity ladder -- which rung to stand on, and what each one costs
- Smoke Tests -- properties of the whole corpus
- Checking components -- validate Airflow extension points before registration
- Airflow 2->3 Migration -- arrive migrating, leave with a suite
- Under the hood -- what
_compat/absorbs, and why
Contributing, the local gate, and running CI with act:
CONTRIBUTING.md and
Developing this plugin.
License
Apache License 2.0. See LICENSE, NOTICE, and PROVENANCE.md.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pytest_airflow_in_a_box-0.13.0.tar.gz.
File metadata
- Download URL: pytest_airflow_in_a_box-0.13.0.tar.gz
- Upload date:
- Size: 358.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
46306530088a05a882b0d6352e436926edb355b5b453274956a8bf6f2bae44d5
|
|
| MD5 |
38a86f1c9a7c697935a6534d3b37d71b
|
|
| BLAKE2b-256 |
9458e518a42e11d59d1bb38d3939100b9b023725988f6108467146e1da7f90e8
|
Provenance
The following attestation bundles were made for pytest_airflow_in_a_box-0.13.0.tar.gz:
Publisher:
release.yml on nredd/pytest-airflow-in-a-box
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pytest_airflow_in_a_box-0.13.0.tar.gz -
Subject digest:
46306530088a05a882b0d6352e436926edb355b5b453274956a8bf6f2bae44d5 - Sigstore transparency entry: 2655391780
- Sigstore integration time:
-
Permalink:
nredd/pytest-airflow-in-a-box@ec4907d2bd025cd67cc6750e607f7b326d6e9c5e -
Branch / Tag:
refs/tags/v0.13.0 - Owner: https://github.com/nredd
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ec4907d2bd025cd67cc6750e607f7b326d6e9c5e -
Trigger Event:
release
-
Statement type:
File details
Details for the file pytest_airflow_in_a_box-0.13.0-py3-none-any.whl.
File metadata
- Download URL: pytest_airflow_in_a_box-0.13.0-py3-none-any.whl
- Upload date:
- Size: 409.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
571f70c4aef62baf2dffd813c11896f22811476beb4300e94583bcb38d6d69c4
|
|
| MD5 |
5c00e7c268c6268f0339d407ae9d61db
|
|
| BLAKE2b-256 |
9007373ccc8df01896821b5ea47e539e9a306e155a0d67be4e843f21fd0c8def
|
Provenance
The following attestation bundles were made for pytest_airflow_in_a_box-0.13.0-py3-none-any.whl:
Publisher:
release.yml on nredd/pytest-airflow-in-a-box
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pytest_airflow_in_a_box-0.13.0-py3-none-any.whl -
Subject digest:
571f70c4aef62baf2dffd813c11896f22811476beb4300e94583bcb38d6d69c4 - Sigstore transparency entry: 2655391787
- Sigstore integration time:
-
Permalink:
nredd/pytest-airflow-in-a-box@ec4907d2bd025cd67cc6750e607f7b326d6e9c5e -
Branch / Tag:
refs/tags/v0.13.0 - Owner: https://github.com/nredd
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ec4907d2bd025cd67cc6750e607f7b326d6e9c5e -
Trigger Event:
release
-
Statement type: