Static analysis and diagnostics for Behave BDD suites.
Project description
behave-doctor
Static analysis and diagnostics for Behave BDD suites.
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-testall coexist, breaking tag filters. - Features balloon in size — 50-scenario features become impossible to review or maintain.
- Circular imports between step modules cause
ImportErrorat 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) andtyper(CLI). Pure Python, fully typed,mypy --strictclean,ruffclean. - Configurable via
[tool.behave-doctor]inpyproject.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, andgraphsubcommands. - 95% test coverage — 192 tests across unit and integration suites.
Installation
pip install behave-doctor
Requirements: Python 3.11+. The behave-model package (for .feature
parsing) 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.
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 = "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
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)
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:
- Scan —
behave-modelparses.featurefiles into an AST. The step scanner uses Python'sastmodule to extract@given/@when/@thendecorators from step modules — without importing them. - Match — Each feature step is matched against step definitions using
the matcher type (
re,parse,cfparse, orbehave's default). The dependency graph records which definitions are used and which are not. - Analyze — 18 rules visit the project, step definitions, and dependency graph to produce diagnostics.
- 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/:
- Installation
- Quick Start
- CLI Reference
- Rules
- Configuration
- Reporters
- Python API
- CI/CD
- Architecture
- FAQ
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.featurefile parser that powers behave-doctor's analysis.typer— the CLI framework that makes behave-doctor's command-line interface clean and ergonomic.ruffandmypy— the tools that keep behave-doctor's codebase clean and fully typed.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file behave_doctor-1.2.0.tar.gz.
File metadata
- Download URL: behave_doctor-1.2.0.tar.gz
- Upload date:
- Size: 86.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f4989c6d50c09d3ea7bdf5d2d6439560fe5e6db95a9011580a7a20aaf79cab72
|
|
| MD5 |
dbf7aa879a84429584acf007c4994160
|
|
| BLAKE2b-256 |
8e20428dd9fdd55cd693120555c51f6556e83f1511a78471ad910fbc1d768bfc
|
Provenance
The following attestation bundles were made for behave_doctor-1.2.0.tar.gz:
Publisher:
release.yml on MathiasPaulenko/behave-doctor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
behave_doctor-1.2.0.tar.gz -
Subject digest:
f4989c6d50c09d3ea7bdf5d2d6439560fe5e6db95a9011580a7a20aaf79cab72 - Sigstore transparency entry: 2224983923
- Sigstore integration time:
-
Permalink:
MathiasPaulenko/behave-doctor@1dd45649bf24aeae9604423bc35fae9b93c45258 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/MathiasPaulenko
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1dd45649bf24aeae9604423bc35fae9b93c45258 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file behave_doctor-1.2.0-py3-none-any.whl.
File metadata
- Download URL: behave_doctor-1.2.0-py3-none-any.whl
- Upload date:
- Size: 46.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8e1d65bd2a493165b071ff3105b514d83e1091a534103a39df24e052641fbfaf
|
|
| MD5 |
65c2df103543215dfd2c6a3b09f500ba
|
|
| BLAKE2b-256 |
0e4efd01838bfcbff3e5f1c80c4f4341b331a008d25c563537693c5082b143a1
|
Provenance
The following attestation bundles were made for behave_doctor-1.2.0-py3-none-any.whl:
Publisher:
release.yml on MathiasPaulenko/behave-doctor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
behave_doctor-1.2.0-py3-none-any.whl -
Subject digest:
8e1d65bd2a493165b071ff3105b514d83e1091a534103a39df24e052641fbfaf - Sigstore transparency entry: 2224984638
- Sigstore integration time:
-
Permalink:
MathiasPaulenko/behave-doctor@1dd45649bf24aeae9604423bc35fae9b93c45258 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/MathiasPaulenko
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1dd45649bf24aeae9604423bc35fae9b93c45258 -
Trigger Event:
workflow_dispatch
-
Statement type: