Skip to main content

behave-doctor

Lint, diagnose, and analyze the impact of changes in your Behave BDD test suites — without running a single test.

CI Docs PyPI Python Coverage License Code style: ruff Types: mypy

behave-doctor inspects your Behave .feature files and Python step definitions without executing them, surfacing issues like unused step definitions, undefined steps, oversized features, inconsistent tags, and circular import dependencies — before they slow down your test suite or confuse your team.

It also includes an impact analysis command: tell it which files you changed, and it tells you exactly which scenarios are affected — so you can run only the tests that matter instead of the full suite.

Why behave-doctor?

Behave suites grow organically. Over time:

  • Step definitions drift from feature files — unused definitions pile up, undefined steps cause runtime failures.
  • Tags accumulate without consistency — @SmokeTest, @smoke_test, and @smoke-test all coexist, breaking tag filters.
  • Features balloon in size — 50-scenario features become impossible to review or maintain.
  • Circular imports between step modules cause ImportError at runtime.
  • No visibility into suite health — how many steps are defined? How many are actually used? How complex are your scenarios?

behave-doctor catches all of these statically — no test execution required, no side effects, no network calls. It parses .feature files with behave-model and analyzes Python step definitions with the AST — never importing or executing them.

Features

  • 20 diagnostic rules across 5 categories:
    • Structure (BD101-104) — feature, scenario, step, and tag counts.
    • Quality (BD201-205) — duplicate definitions, missing tags, oversized features, inconsistent tag casing, ambiguous step matches.
    • Coverage (BD301-305) — unused step definitions, undefined steps, unused tags, orphan scenarios, unparseable feature files.
    • Complexity (BD401-403) — scenario step count, step parameter count, feature file size.
    • Dependencies (BD501-503) — circular imports, unused imports, missing step modules.
  • Impact analysis — given a list of changed .py or .feature files, determines which scenarios are affected and outputs names suitable for behave --name, JSON, or human-readable text.
  • 4 output formats: human-readable text (with ANSI colors), JSON, SARIF 2.1.0 for GitHub Code Scanning, and names for impact analysis.
  • Minimal runtime dependencies — only behave/behave-model (parsing and matching) and typer (CLI). Pure Python, fully typed, mypy --strict clean, ruff clean.
  • Configurable via [tool.behave-doctor] in pyproject.toml — per-rule thresholds, enable/disable, severity filtering, tag exclusions.
  • Python API for embedding in custom tooling, IDE plugins, or CI integrations.
  • CLI with scan, impact, list-rules, explain, stats, and graph subcommands.
  • 97% test coverage — 313 tests across unit and integration suites.

Installation

pip install behave-doctor

Requirements: Python 3.11+. The behave and behave-model packages (for .feature parsing and step matching) and typer (for the CLI) are installed automatically.

Quick start

behave-doctor scan .
Scanning . ...
Found 12 features, 47 scenarios, 213 steps, 89 step definitions.

BD101  INFO      12 features found
BD102  INFO      47 scenarios found
BD103  INFO      213 steps found
BD201  ERROR     Duplicate step definition for pattern 'the user is logged in' in: ...
BD301  WARNING   Unused step definition: "the user clicks submit"  (features/steps/auth.py:42)
BD302  ERROR     Undefined step: "Given the database is seeded"  (features/login.feature:18)

3 errors, 1 warning in 0.42s

Exit codes: 0 = clean, 1 = issues found, 2 = scan error.

Impact analysis

Tell behave-doctor which files you changed, and it tells you which scenarios are affected — so you can run only the tests that matter.

# Which scenarios are affected by changes to login_steps.py?
behave-doctor impact . --changed-files features/steps/login_steps.py
Impact analysis: 1 changed files

Changed files:
  - /path/to/features/steps/login_steps.py (4 step definitions)

Affected scenarios (4):
  /path/to/features/login.feature:3  Successful login
  /path/to/features/login.feature:11  Failed login
  /path/to/features/search.feature:5  Search by keyword
  /path/to/features/search.feature:12  Search with filter

Affected features (2):
  /path/to/features/login.feature
  /path/to/features/search.feature

Get scenario names for behave --name:

behave-doctor impact . --changed-files features/steps/login_steps.py --format names
Successful login
Failed login
Search by keyword
Search with filter

Pipe directly to Behave:

behave-doctor impact . --changed-files features/steps/login_steps.py --format names | xargs -I{} behave --name "{}"

JSON output for CI integration:

behave-doctor impact . --changed-files features/steps/login_steps.py --format json

Impact analysis understands Background steps — if a changed step definition is used in a feature's Background, all scenarios in that feature are affected.

Rules

ID Name Severity Category Configurable
BD101 feature-count info Structure No
BD102 scenario-count info Structure No
BD103 step-count info Structure No
BD104 tag-coverage info Structure No
BD201 duplicate-step-defs error Quality No
BD202 scenario-no-tags warning Quality No
BD203 feature-too-many-scenarios warning Quality max_scenarios (default 20)
BD204 inconsistent-tag-casing warning Quality No
BD205 ambiguous-step-match error Quality No
BD301 unused-step-def warning Coverage No
BD302 undefined-step error Coverage No
BD303 unused-tag info Coverage exclude_tags (global)
BD304 orphan-scenario warning Coverage No
BD305 unparseable-feature error Coverage No
BD401 scenario-too-many-steps warning Complexity max_steps (default 10)
BD402 step-too-many-params warning Complexity max_params (default 5)
BD403 feature-too-large warning Complexity max_lines (default 300)
BD501 circular-dependency error Dependency No
BD502 unused-import warning Dependency No
BD503 missing-step-module error Dependency No

Explore rules from the CLI:

behave-doctor list-rules          # list all 20 rules
behave-doctor explain BD301       # explain a specific rule

Configuration

All options have sensible defaults — configuration is optional.

# pyproject.toml
[tool.behave-doctor]
features_dir = "features/"          # default: features/
steps_dir = "features/steps/"       # default: features/steps/
min_severity = "info"               # default: info (show errors, warnings, and info)
exclude_tags = ["@smoke", "@wip"]   # tags excluded from BD303

[tool.behave-doctor.rules.BD101]    # disable a rule
enabled = false

[tool.behave-doctor.rules.BD203]    # adjust a threshold
max_scenarios = 15

[tool.behave-doctor.rules.BD401]
max_steps = 8

[tool.behave-doctor.rules.BD402]
max_params = 3

[tool.behave-doctor.rules.BD403]
max_lines = 200

CLI flags override config file values:

behave-doctor scan . --severity error --rules BD301,BD302 --exclude-rules BD101

Output formats

# Human-readable (default, with ANSI colors)
behave-doctor scan . --format text

# JSON for CI integration and custom tooling
behave-doctor scan . --format json

# SARIF 2.1.0 for GitHub Code Scanning
behave-doctor scan . --format sarif -o behave-doctor.sarif

Python API

Scanning

from behave_doctor import scan_project, Severity

report = scan_project("path/to/project")

# Filter diagnostics by severity
errors = [d for d in report.diagnostics if d.severity is Severity.ERROR]
for d in errors:
    print(f"{d.rule_id}: {d.message} at {d.file}:{d.line}")

# Access statistics
stats = report.statistics
print(f"{stats.features} features, {stats.scenarios} scenarios")
print(f"{stats.unused_step_definitions} unused, {stats.undefined_steps} undefined")

# Exit code: 0 = clean, 1 = issues found
print(f"Exit code: {report.exit_code}")

Custom configuration:

from behave_doctor import scan_project, DoctorConfig, Severity

config = DoctorConfig(
    features_dir="my_features",
    steps_dir="my_steps",
    min_severity=Severity.WARNING,
    rules={"BD101": {"enabled": False}, "BD401": {"max_steps": 5}},
)
report = scan_project("path/to/project", config=config)

Impact analysis

from behave_doctor import impact_analysis, format_impact

result = impact_analysis(
    "path/to/project",
    changed_files=["features/steps/login_steps.py"],
)

# Affected scenario names (suitable for behave --name)
for name in result.scenario_names:
    print(name)

# Summary counts
print(f"{result.summary.scenarios_affected} scenarios affected")
print(f"{result.summary.features_affected} features affected")

# Format as text, JSON, or names
print(format_impact(result, "text"))
print(format_impact(result, "json"))
print(format_impact(result, "names"))

CI/CD

GitHub Actions (basic lint)

- run: pip install behave-doctor
- run: behave-doctor scan . --no-color

GitHub Code Scanning (SARIF)

- run: pip install behave-doctor
- run: behave-doctor scan . --format sarif -o behave-doctor.sarif
  continue-on-error: true
- uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: behave-doctor.sarif

Pre-commit hook

repos:
  - repo: https://github.com/MathiasPaulenko/behave-doctor
    rev: v1.4.0
    hooks:
      - id: behave-doctor
        args: ["scan", "--severity", "warning", "--no-color"]

How it works

behave-doctor never executes your code. It works in four phases:

  1. Scan — behave-model parses .feature files into an AST. The step scanner uses Python's ast module to extract @given/@when/@then decorators from step modules — without importing them.
  2. Match — Each feature step is matched against step definitions using Behave's own matcher classes (parse, cfparse, re, re0), honouring use_step_matcher calls in each module. The dependency graph records which definitions are used and which are not.
  3. Analyze — 20 rules visit the project, step definitions, and dependency graph to produce diagnostics.
  4. Report — Diagnostics are formatted as text, JSON, or SARIF and written to stdout or a file.

Documentation

Full documentation at https://mathiaspaulenko.github.io/behave-doctor/:

Supply chain & trust

  • Trusted Publishing (OIDC) — releases to PyPI use Trusted Publishing via GitHub Actions OIDC. No long-lived API tokens are stored in secrets.
  • Pinned actions — all GitHub Actions are pinned to specific versions (e.g. @v4, @v1.12.4).
  • Minimal dependencies — only behave/behave-model (parsing and matching) and typer (CLI) at runtime. No transitive dependency tree to audit.
  • No code execution — behave-doctor never imports or executes your step definitions. It uses Python's ast module for static analysis only.
  • py.typed marker — the package ships with inline type hints.
  • Reproducible builds — hatchling build backend with no dynamic metadata.

Development

git clone https://github.com/MathiasPaulenko/behave-doctor.git
cd behave-doctor
pip install -e ".[dev]"
pre-commit install
Command Description
make help Show all available targets.
make dev Install with dev extras.
make lint Run ruff check + mypy --strict.
make lint-fix Auto-fix lint issues.
make format Format the code with ruff format.
make format-check Verify formatting without changes.
make test Run the test suite.
make test-cov Run tests with coverage (fail under 90%).
make check Full pre-commit check (lint + format + test).
make build Build sdist + wheel into dist/.
make docs-serve Serve documentation locally.
make clean Remove build artifacts and caches.

See CONTRIBUTING.md for full guidelines.

License

MIT — © Mathias Paulenko

Acknowledgements

  • behave-model — the .feature file parser that powers behave-doctor's analysis.
  • typer — the CLI framework that makes behave-doctor's command-line interface clean and ergonomic.
  • ruff and mypy — the tools that keep behave-doctor's codebase clean and fully typed.

Metadata

Release files for behave-doctor 1.4.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 behave-doctor 1.4.0
File Size Uploaded
behave_doctor-1.4.0.tar.gz 111.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for behave-doctor 1.4.0
File Interpreter ABI Platform
behave_doctor-1.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 170.8 kB

Release files / behave_doctor-1.4.0.tar.gz

Download URL behave_doctor-1.4.0.tar.gz
Size 111.5 kB
Tags Source
SHA-256 checksum
How to use checksums
59102333bf2d32e5ec2d7702d24ffb74a8adc5e5a4f61b74077f44eae0cdb5e2
BLAKE2b-256 checksum
How to use checksums
7cad4a02973864539c61193b006fb9fe1cde0353cf03a98b04429cee14325704
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Oct 2, 2026.

Transparency log

Release files / behave_doctor-1.4.0-py3-none-any.whl

Download URL behave_doctor-1.4.0-py3-none-any.whl
Size 59.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8ca8c1b6fb791d50c900fafda497a835ee49bf3e4e1c0b2b3e446cca434ef6fe
BLAKE2b-256 checksum
How to use checksums
a14ba53308876ec1fb11e2f242ab161a33d80251fde9284ed57fb05f63178303
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Oct 2, 2026.

Transparency log

Release history Release notifications | RSS feed

1.5.1

2 release files

1.5.0

2 release files

This release

1.4.0 This release

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.0

2 release files

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