Skip to main content

Static analysis and diagnostics for Behave BDD suites.

Project description

behave-doctor

Static analysis and diagnostics for Behave BDD suites.

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.

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

  • 18 diagnostic rules across 5 categories:
    • Structure (BD101-104) — feature, scenario, step, and tag counts.
    • Quality (BD201-204) — duplicate definitions, missing tags, oversized features, inconsistent tag casing.
    • Coverage (BD301-304) — unused step definitions, undefined steps, unused tags, orphan scenarios.
    • Complexity (BD401-403) — scenario step count, step parameter count, feature file size.
    • Dependencies (BD501-503) — circular imports, unused imports, missing step modules.
  • 3 output formats: human-readable text (with ANSI colors), JSON, and SARIF 2.1.0 for GitHub Code Scanning.
  • Minimal runtime dependencies — only behave-model (parsing) 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, list-rules, explain, stats, and graph subcommands.
  • 94% test coverage — 129 tests across unit and integration suites.

Installation

pip install behave-doctor

Requires Python 3.11+. The behave-model package is installed automatically.

Quick start

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

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)

1 errors, 1 warnings in 0.42s

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

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
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
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 18 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 = "hint"               # default: hint (show everything)
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

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, 2 = scan error
print(f"Exit code: {report.exit_code}")

Custom configuration:

from behave_doctor import scan_project, DoctorConfig

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

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.1.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. Scanbehave-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 the matcher type (re, parse, cfparse, or behave's default). The dependency graph records which definitions are used and which are not.
  3. Analyze — 18 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/:

Development

git clone https://github.com/MathiasPaulenko/behave-doctor.git
cd behave-doctor
pip install -e ".[dev]"
pre-commit install
Command Description
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 build Build sdist + wheel into dist/.
make clean Remove build artifacts and caches.

See CONTRIBUTING.md for full guidelines.

License

MIT — © Mathias Paulenko

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

behave_doctor-1.1.0.tar.gz (66.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

behave_doctor-1.1.0-py3-none-any.whl (39.5 kB view details)

Uploaded Python 3

File details

Details for the file behave_doctor-1.1.0.tar.gz.

File metadata

  • Download URL: behave_doctor-1.1.0.tar.gz
  • Upload date:
  • Size: 66.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for behave_doctor-1.1.0.tar.gz
Algorithm Hash digest
SHA256 20dc3de7a5a8d833d81b7de84c3bc2fdd8f1ae75a939a2192abed760add886d1
MD5 409cf2598083da6474b81f41baaa00b2
BLAKE2b-256 15d2fd86fc696b30bd9c56771a6625d2255378511ca791bde165ff0872ca2de0

See more details on using hashes here.

Provenance

The following attestation bundles were made for behave_doctor-1.1.0.tar.gz:

Publisher: release.yml on MathiasPaulenko/behave-doctor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file behave_doctor-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: behave_doctor-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 39.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for behave_doctor-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0053c021d9578b9ca7a405af8c6cd1c7c5f7dd492dcd31c65b917b4d2ce1366e
MD5 e1c326b4f3819a11eb5136d0d09facc4
BLAKE2b-256 4d17a1354f8ea0dc5a755da975c338e2cd0250c35df0eadb5dbf4f8ac6ee1085

See more details on using hashes here.

Provenance

The following attestation bundles were made for behave_doctor-1.1.0-py3-none-any.whl:

Publisher: release.yml on MathiasPaulenko/behave-doctor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page