behave / pytest-bdd Setup
behave and pytest-bdd connect Gherkin feature files to Python step definitions. pytest-bdd integrates with existing pytest suites; behave is a standalone BDD runner.
Search across all documentation pages
behave and pytest-bdd connect Gherkin feature files to Python step definitions. pytest-bdd integrates with existing pytest suites; behave is a standalone BDD runner.
# pytest-bdd (recommended with pytest)
uv add --group dev pytest-bdd
# behave (standalone)
uv add --group dev behaveproject/
├── features/
│ ├── invoice.feature
│ └── steps/
│ └── invoice_steps.py
└── tests/
└── test_bdd.py
When to reach for this:
# features/invoice.feature
Feature: Invoice API
Scenario: Create draft invoice
Given the API is running
When I POST /invoices with amount 100.00
Then the response status is 201# features/steps/invoice_steps.py (pytest-bdd)
from pytest_bdd import scenarios, given, when, then, parsers
from fastapi.testclient import TestClient
from myapp.main import app
scenarios("../invoice.feature")
client = TestClient(app)
_context = {}
@given("the API is running")
def api_running():
_context["client"] = client
@when(parsers.parse("I POST /invoices with amount {amount:f}"))
def post_invoice(amount):
_context["response"] = _context["client"].post(
"/invoices", json={"amount": amount, "currency": "USD"}
)
@then(parsers.parse("the response status is {status:d}"))
def check_status(status):
assert _context["response"].status_code == statusuv run pytest features/steps/invoice_steps.py -vWhat this demonstrates:
features/ directoryscenarios() links feature to step module@given/@when/@then decorators map Gherkin to Pythonparsers.parse extracts parameters from step text| Aspect | pytest-bdd | behave |
|---|---|---|
| Runner | pytest | behave CLI |
| Fixtures | pytest fixtures in steps | behave context object |
| Integration | Same suite as unit tests | Separate features/ runner |
| Parser | @given(parsers.parse(...)) | @when('{amount:f}') parse format |
features/
├── environment.py # hooks: before_all, after_scenario
├── invoice.feature
└── steps/
└── invoice_steps.py
uv run behave features/context per scenario.scenarios() import in a collected test module.| Alternative | Use When | Don't Use When |
|---|---|---|
| Plain pytest | No stakeholder-readable specs | BDD process adopted |
| Robot Framework | Keyword-driven, non-dev authors | Python-native steps preferred |
pytest-bdd if already on pytest. behave for standalone BDD projects.
features/ at project root is the convention for both tools.
Yes with pytest-bdd. Request fixtures as step function parameters.
pytest-bdd: pytest -k scenario_name. behave: behave features/invoice.feature.
Import step modules or put common steps in features/steps/common_steps.py.
Yes. Examples table maps to parametrized scenarios automatically.
features/environment.py with before_scenario, after_all, etc.
Yes. Use Django test client in step definitions with pytest-django.
@smoke above Scenario. Filter: behave --tags=smoke or pytest markers.
pytest --pdb or add logging in step definitions. behave: --no-capture.
Stack versions: This page was written for Python 3.14.0, FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 19, 2026