Skip to main content
pytest-beehave

Python License PyPI CI

Generates pytest test stubs from Gherkin .feature files, checks consistency, and displays BDD steps — automatically, every time pytest runs.


pytest-beehave is a pytest plugin powered by beehave. It reads your Gherkin .feature files and generates Hypothesis-compatible test stubs with the right names, decorators, and parameters — then verifies that your test code stays consistent with your spec. New scenarios get @pytest.mark.skip; drift becomes a real test failure.

pip install pytest-beehave

No conftest.py changes required. The plugin registers itself via pytest's entry-point system.

Optional: install pytest-beehave[html] for a "Scenario" column in pytest-html reports.

pip install "pytest-beehave[html]"

Quick start

1. Write a feature file

# docs/features/checkout/shopping_cart.feature
Feature: Shopping cart

  Background:
    Given an empty cart

  Rule: Tax calculation

    Scenario: VAT is applied at the correct rate
      Given a cart with items totalling $100
      When the buyer is in the UK
      Then the order total is $120

2. Run pytest

pytest --collect-only

3. A test stub is created

tests/features/shopping_cart/
├── tax_calculation_test.py
# tests/features/shopping_cart/tax_calculation_test.py
import pytest

@pytest.mark.skip(reason="not implemented")
def test_VAT_is_applied_at_the_correct_rate():
    ...

4. See BDD steps

pytest -v
tests/features/shopping_cart/tax_calculation_test.py::test_VAT_is_applied_at_the_correct_rate SKIPPED
  Given an empty cart
  Given a cart with items totalling $100
  When the buyer is in the UK
  Then the order total is $120

5. Implement and ship

Remove @pytest.mark.skip, write the test body, run pytest again. The steps display stays in sync with your feature file.


How it works

The plugin hooks into pytest_configure — every stub exists on disk before collection begins.

pytest invoked
  └─ pytest_configure fires
       ├─ load_config()                  → read [tool.beehave] from pyproject.toml
       ├─ parse_feature()                → parse .feature files into ScenarioInfo
       ├─ generate_stubs()               → write Hypothesis test stubs to disk
       ├─ _add_skip_markers()            → mark unimplemented stubs with @pytest.mark.skip
       ├─ check_all()                    → detect drift between features and tests
       └─ register display plugins       → StepsReporter (-v) and/or HtmlStepsPlugin
  └─ pytest_collection_modifyitems       → inject failing tests for ERROR violations
  └─ Collection begins — every stub is already present

File layout

docs/features/              ← configured via features_dir
  **/*.feature              ← any subfolder structure is supported

tests/features/             ← configured via tests_dir
  <feature_slug>/           ← one directory per feature (derived from Feature title)
    <rule_slug>_test.py     ← one file per Rule: block (or default_test.py)

Each test function name follows test_<scenario_title_with_underscores>. The mapping is exact string equality — no @id tags, no step definitions, no glue code.


What check_all enforces

After stub generation, the plugin runs check_all() to detect drift between feature files and test code. ERROR violations produce real test failures via synthetic test items:

Type Severity What it catches
unmapped-scenario ERROR Scenario has no matching test function
unmapped-test ERROR Test function has no matching scenario
misplaced-test WARNING Function is in the wrong rule file
missing-placeholder ERROR Test body missing a <placeholder>
missing-literal ERROR Test body missing a "string" or numeric literal
example-mismatch ERROR Examples rows don't match @example() decorators
$ pytest
[beehave] ERROR: tests/features/demo/default_test.py:5: unmapped-test: 'test_orphan' has no matching scenario
========================= 1 failed, 3 passed, 2 skipped =========================

Stub functions (body is ...) are excluded from placeholder and literal checks.


How it maps

  • Scenario title → function name: VAT Is Applied At The Correct Rate → test_VAT_is_applied_at_the_correct_rate. Lowercased. Globally unique.
  • Rule → test file: Top-level scenarios go to default_test.py. Scenarios inside a Rule go to <rule>_test.py.
  • Feature title → directory: Shopping Cart → tests/features/shopping_cart/.
  • Scenario Outline → decorators: <placeholder> columns become @given() parameters with inferred Hypothesis strategies. Example rows become @example() decorators.

TDD workflow

  1. pytest --collect-only → stubs generated with @pytest.mark.skip
  2. Remove @pytest.mark.skip, write the test body → test runs and fails (red)
  3. Fix the implementation → test passes (green)
  4. Add new scenarios to .feature files → only new stubs get the skip marker

Configuration

All configuration lives under [tool.beehave] in pyproject.toml:

[tool.beehave]
features_dir = "docs/features"      # default: docs/features
tests_dir = "tests/features"        # default: tests/features
default_strategy = "text"           # default: text (Hypothesis strategy for placeholders)
background_check_numeric = true     # default: true
background_check_string = true      # default: true

If features_dir does not exist, the plugin exits silently.


Requirements

Version
Python >= 3.14
pytest >= 6.0
beehave >= 1.0.0

Contributing

git clone https://github.com/nullhack/pytest-beehave
cd pytest-beehave
uv sync --all-extras
uv run task test && uv run task lint && uv run task static-check

Bug reports and pull requests welcome on GitHub.


License

MIT — see LICENSE.

Metadata

Release files for pytest-beehave 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pytest-beehave 1.0.0
File Size Uploaded Provenance Actions
pytest_beehave-1.0.0.tar.gz 13.3 kB With provenance Details for pytest_beehave-1.0.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for pytest-beehave 1.0.0
File Interpreter ABI Platform Actions
pytest_beehave-1.0.0-py3-none-any.whl Python 3 none any Details for pytest_beehave-1.0.0-py3-none-any.whl

Total release size: 23.5 kB

Release files / pytest_beehave-1.0.0.tar.gz

Download URL pytest_beehave-1.0.0.tar.gz
Size 13.3 kB
Tags Source
SHA-256 checksum
How to use checksums
e2d745027a58619a06568b3bdb2f88986be6bb4a863e2c5c6fe1a2824cdf2c71
BLAKE2b-256 checksum
How to use checksums
85295137c2909394ae2933e5be6aa034a7584c9e7e66b7731e46042408f7e6e4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 20, 2026.

Transparency log

Release files / pytest_beehave-1.0.0-py3-none-any.whl

Download URL pytest_beehave-1.0.0-py3-none-any.whl
Size 10.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2cbcfdf44fc6f328590e324901388731596f0d4c2ab402a593a79363e6b1bd8d
BLAKE2b-256 checksum
How to use checksums
8d606c0e9ca196f6634a0cc1654b6ea0f46e41269ad3b5868ceae241ed901e20
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 20, 2026.

Transparency log

Security for pytest-beehave 1.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for pytest_beehave-1.0.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 20, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page