Skip to main content

The Swiss-army knife for Behave — soft assertions, typed context, conditional skip, env management, fixtures and more.

Project description

behave-kit

The Swiss-army knife for Behave — soft assertions, typed context, conditional skip, environment management, fixtures and more.

CI Coverage PyPI Python 3.11+ License: MIT

Why behave-kit?

Behave is great for BDD, but real test suites need more than Given/When/Then. You need to:

  • Collect multiple assertion failures without stopping at the first one
  • Skip steps based on environment, OS, or missing dependencies
  • Read environment variables with type conversion and validation
  • Load test data from CSV, JSON, YAML, or Excel files
  • Manage fixtures with automatic setup/teardown by tag
  • Get IDE autocompletion for context attributes
  • Debug failures with automatic context dumps
  • Poll for conditions with configurable timeout and interval
  • Assert expected exceptions as part of soft assertion collections
  • Run data-driven steps from CSV, JSON, YAML, or Excel files
  • Isolate environment variables with snapshot/restore context managers
  • Navigate nested dicts with dot notation
  • Assert execution time with assert_under and @timed
  • Create temp directories for filesystem-isolated tests

behave-kit provides all of these as independent, opt-in utilities — no monkey-patching, no breaking changes.

Installation

pip install behave-kit

With optional extras:

pip install "behave-kit[yaml,excel,dotenv]"
Extra Provides Dependency
yaml YAML data loading pyyaml>=6.0
excel XLSX data loading openpyxl>=3.1
dotenv .env file loading python-dotenv>=1.0
docs Sphinx documentation build sphinx, furo, myst-parser
dev Development tools pytest, ruff, mypy, build, pre-commit

Quickstart

Level 1 — Automatic wiring

Add two lines to your environment.py and every feature is wired automatically:

from behave_kit import setup, teardown

def before_all(context):
    setup(context, env="staging")

def after_scenario(context, scenario):
    teardown(context)

Level 2 — Cherry-pick

Import only what you need:

from behave_kit import assert_soft, env, load_data

@then("the response should be valid")
def step(context):
    assert_soft(context.response.status_code == 200)
    api_key = env("API_KEY", required=True)
    users = load_data("tests/data/users.csv")

Level 3 — Namespace

import behave_kit as bk

@then("the response should be valid")
def step(context):
    bk.assert_soft(context.response.status_code == 200)

Features

Soft assertions

Collect multiple failures and report them all at once:

from behave_kit import assert_soft

assert_soft(response.status_code == 200)
assert_soft(response.body["count"] > 0)
assert_soft("error" not in response.body)
# All failures reported together at teardown

TypedContext

Schema-validated proxy with IDE autocompletion and mypy support:

from behave_kit import TypedContext

class MySchema:
    driver: str
    base_url: str

ctx = TypedContext(context, MySchema)
ctx.setup(driver="chrome", base_url="https://test.com")
print(ctx.driver)  # IDE autocompletion works

Conditional skip

Skip steps by environment, OS, or missing dependency:

from behave_kit import skip_if_env, skip_if_no_browser, skip_on_os, skip_if_missing

@skip_if_env("production")
@when("I run the staging-only step")
def step(context): ...

@skip_if_no_browser
@when("I open the browser")
def step(context): ...

@skip_on_os("windows")
@when("I run the unix-only step")
def step(context): ...

@skip_if_missing("selenium")
@when("I use selenium")
def step(context): ...

Environment variables

Typed reads with defaults, validation, and config file fallback:

from behave_kit import env

api_key = env("API_KEY", required=True)                    # str
timeout = env("TIMEOUT", var_type=int, default=30)         # int
debug = env("DEBUG", var_type=bool, default=False)         # bool

Data loading

Single API for CSV, JSON, YAML, and Excel:

from behave_kit import load_data

users = load_data("tests/data/users.csv")       # list[dict]
config = load_data("tests/data/config.json")    # dict
sheet = load_data("tests/data/sheet.xlsx")      # list[dict] (requires [excel])

Fixtures

Tag-based setup/teardown with dependency resolution:

from behave_kit import fixture

@fixture("browser")
def browser_fixture(context):
    def setup(ctx):
        ctx.browser = start_browser()
    def teardown(ctx):
        ctx.browser.quit()
    return (setup, teardown)

@fixture("database", requires="browser")
def database_fixture(context):
    ...

Context dump

Automatic context snapshot on scenario failure for easier debugging:

from behave_kit import dump_context_on_failure
# Wired automatically by setup(), or call manually

Step suggestions

"Did you mean?" hints for undefined steps:

from behave_kit import setup_suggestions
# Wired automatically by setup()

Scoped attributes

Automatic cleanup of context attributes per scenario:

from behave_kit import scoped

@scoped("driver")
@when("I start the driver")
def step(context):
    context.driver = start_driver()
# "driver" is automatically deleted after the scenario

Conditional steps

Run a step only when a condition holds:

from behave_kit import when_if

@when_if(lambda ctx: ctx.config.env == "staging")
@when("I run the staging-only step")
def step(context): ...

Parameter types

Register custom Behave parameter types:

from behave_kit import parameter_type

@parameter_type("User", r"[\w.]+@[\w.]+\.[a-z]+")
def parse_user(text):
    return User(name=text)

Soft exception assertions

Check that a callable raises an expected exception, collected as a soft failure:

from behave_kit import assert_soft_raises

assert_soft_raises(ValueError, lambda: int("abc"))
assert_soft_raises(KeyError, lambda: {}["missing"])
# Failures are collected and reported together at teardown

Data-driven steps

Run a step once per row of a data file, with column names injected as keyword arguments:

from behave_kit import data_driven

@data_driven("tests/data/users.csv")
@when("I login as {username}")
def step(context, username=None, password=None):
    login(username, password)
# Runs once per row in users.csv

Environment variable snapshot

Save and restore os.environ so tests don't leak environment variable changes:

from behave_kit import env_snapshot

with env_snapshot():
    os.environ["API_KEY"] = "test"
    # ... test ...
# API_KEY restored automatically

Dict navigation with get_path

Extract values from nested dicts using dot notation:

from behave_kit import get_path

city = get_path(response, "user.address.city")           # "Berlin"
name = get_path(response, "users.0.name", default="?")   # "Alice"

Time assertions

Assert that a callable completes within a time limit:

from behave_kit import assert_under, timed

assert_under(2.0, lambda: client.get("/health"))

@timed(1.5)
@when("I fetch the data")
def step(context): ...

Wait until

Poll a condition until it becomes true or a timeout is reached:

from behave_kit import wait_until

wait_until(lambda: context.response.status_code == 200, timeout=10, interval=0.5)

Temp workspace

Create an isolated temporary directory and restore the CWD on exit:

from behave_kit import temp_workspace

with temp_workspace() as tmp:
    config_path = tmp / "config.json"
    config_path.write_text("{}")
# Directory is cleaned up automatically

Documentation

Full documentation is available at mathiaspaulenko.github.io/behave-kit.

To build docs locally:

pip install "behave-kit[docs]"
cd docs && sphinx-build -b html . _build/html

Development

See CONTRIBUTING.md for development setup, coding standards, and contribution guidelines.

License

MIT — see LICENSE.

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_kit-1.2.0.tar.gz (76.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_kit-1.2.0-py3-none-any.whl (49.8 kB view details)

Uploaded Python 3

File details

Details for the file behave_kit-1.2.0.tar.gz.

File metadata

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

File hashes

Hashes for behave_kit-1.2.0.tar.gz
Algorithm Hash digest
SHA256 3153671135f845791110decd2908d3d897ed0f4e58fee0b679a6cfdf41bf8247
MD5 405b0b04ff56b39eb8044f5ae77e95af
BLAKE2b-256 f053cbf9c0d7501f962f21bbaabf298fde9ddc8dce3af0cd0d8efe8c8f8d82e4

See more details on using hashes here.

Provenance

The following attestation bundles were made for behave_kit-1.2.0.tar.gz:

Publisher: release.yml on MathiasPaulenko/behave-kit

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_kit-1.2.0-py3-none-any.whl.

File metadata

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

File hashes

Hashes for behave_kit-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 befc2934d35314198c2de2616b7eba9e3f4a9f8783156faae0304abe40a68309
MD5 a9462fdb6fa075c1b150e0312299eca5
BLAKE2b-256 95e0deb1a7b3d662574af12a41afde1e0b218cd02315ddb5727051fd9b5aba10

See more details on using hashes here.

Provenance

The following attestation bundles were made for behave_kit-1.2.0-py3-none-any.whl:

Publisher: release.yml on MathiasPaulenko/behave-kit

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