Fabien Punin
09/06/2025, 10:24 PMMarvin
09/06/2025, 10:24 PMMarvin
09/06/2025, 10:25 PMflow.fn()
, any @task
calls inside that flow run as plain Python functions. They will not create task runs, won’t talk to a Prefect backend, and none of the Prefect runtime features (retries, caching, timeouts, task state, get_run_logger()
, etc.) are active.
Recommended testing patterns:
- Unit test tasks as pure functions:
@task
def add(x, y):
return x + y
def test_add_unit():
assert add.fn(1, 2) == 3
- Unit test flows without Prefect orchestration:
@flow
def pipeline():
return add(1, 2)
def test_pipeline_unit():
assert pipeline.fn() == 3 # tasks inside run as plain functions
- Lightweight integration tests (exercise Prefect engine without a backend):
- Call pipeline()
(not .fn()
), but ensure your test environment is not configured with an API URL. In Prefect 3.x, if you haven’t set an API URL, local runs won’t hit any backend.
- Practically, run tests under a Prefect profile that does not set PREFECT_API_URL
(or unset it in your test environment).
Notes/caveats when using `.fn()`:
- No retries, caching, timeouts, or concurrency — it’s just Python.
- Calls to get_run_logger()
or anything that requires a flow/task run context will not work.
Docs:
- How to test Prefect workflows: Testing workflows in Prefect 3
If you want, I can show a pytest fixture pattern that temporarily unsets PREFECT_API_URL
for integration-style tests.