configuration

Configuration

Behave loads two Raku-based configuration files at startup and merges them with your CLI flags. This is the standard way to keep team-wide and machine-wide defaults out of every spec invocation.

File format

A .behave file is a Raku script. It calls configure-behave with a block that receives a Configuration object:

use BDD::Behave::Configuration;

configure-behave -> $config {
  $config.format = 'documentation';
  $config.order  = 'random';
  $config.seed   = 12345;

  $config.include-tag('focus');
  $config.exclude-tag('slow');

  $config.aggregate-failures = True;
  $config.fail-fast          = 1;
}

Because the file is plain Raku, you can pull in helpers (use ...;) and compute values, but each configure-behave block should be self-contained: anything you set inside the block is stored on $config for the run.

Precedence

When more than one source sets the same option, the highest-precedence source wins:

  1. CLI flags (highest): explicit --format, --order, --tag, etc.

  2. Project config: .behave in the current working directory.

  3. User config: ~/.behave in the user's home directory.

  4. Built-in defaults (lowest): what Behave uses when nothing else is set.

List-style options (include-tag, exclude-tag, example-pattern, only-location, spec-paths, include, hooks) accumulate across all four layers: a tag listed in ~/.behave and another listed on the CLI both apply. Scalar options like format, order, seed, fail-fast, verbose, and aggregate-failures override: the highest-precedence layer that sets them wins.

Disabling configuration

Three CLI flags and one environment variable bypass config loading:

Flag / envEffect
--config PATHLoad PATH as the only config, skipping ~/.behave and ./.behave.
--no-configSkip both default config files entirely.
--no-user-configSkip ~/.behave, but still read ./.behave.
--no-project-configSkip ./.behave, but still read ~/.behave.
BEHAVE_DISABLE_CONFIG=1Same as --no-config. Useful for CI and subprocess testing.

--config PATH errors with exit code 2 if PATH does not exist.

Settings

Every scalar attribute corresponds to its CLI counterpart:

Configuration attributeCLI flagNotes
$config.format--formatA registered formatter name (e.g. 'progress').
$config.order--order'random' or 'defined'.
$config.seed--seedInt, only meaningful for 'random'.
$config.fail-fast--fail-fast[=N]0 disables, N >= 1 stops after N failures.
$config.verbose--verboseBool.
$config.aggregate-failures--aggregate-failures[=LABEL]Bool or Str label.
$config.profile-limit--profile[=N]0 disables, N shows top-N slow examples.
$config.slow-threshold--slow-thresholdReal seconds.
$config.benchmark-mode--benchmarkBool.
$config.benchmark-iterations--benchmark-iterationsPositive Int.
$config.benchmark-baseline--benchmark-baselineIO::Path.
$config.benchmark-save--benchmark-saveIO::Path.
$config.benchmark-threshold--benchmark-thresholdReal fraction (0.10 = 10%).
$config.benchmark-format--benchmark-format'text' or 'json'.
$config.benchmark-output--benchmark-outputIO::Path.
$config.parallel--parallel NInt >= 1 enables parallel execution with N worker subprocesses. Absence (or value 0) keeps single-process serial execution. CLI overrides config.
$config.parallel-mode--parallel-mode'isolated' (default), 'lpt', or 'queue'. See Parallel Execution.
$config.parallel-retry--parallel-retryNon-negative Int. Per-shard retry budget when a worker crashes (exit > 1). See Per-shard retry.
$config.seed-mode--seed-mode'xor' (default) or 'stable'.
$config.show-seed--show-seedBool. Print the seed even on a passing run (default prints it only on failure).
$config.progress-total--progress-totalBool. Append a (N/TOTAL) counter to each progress char under --parallel.

The list-style mutators are repeatable:

configure-behave -> $config {
  $config.include-tag('focus', 'wip');
  $config.exclude-tag('slow');
  $config.example-pattern('checkout flow');
  $config.only-location('specs/users-spec.raku:42');
  $config.include-spec('specs/');
}

include-spec populates the default list of spec paths used when no paths are passed on the CLI.

Helper inclusion

$config.include(SomeClass) instantiates SomeClass once for the run and exposes it inside every example via the $*BEHAVE-HELPERS dynamic variable, keyed by the class's short name:

class APIHelpers {
  method as-user($name) { ... }
  method json-post(...) { ... }
}

configure-behave -> $config {
  $config.include(APIHelpers);
}

Inside a spec:

it 'creates a new order', {
  my $resp = $*BEHAVE-HELPERS<APIHelpers>.as-user('alice');
  expect($resp.status).to.eq(201);
}

Use :as<key> to choose a custom key, which is helpful when class names clash or you want a shorter accessor:

$config.include(APIHelpers, :as<api>);
# $*BEHAVE-HELPERS<api>.as-user('alice')

One instance is created per class per run (cached in the runner). State stored on a helper persists across all examples in the suite, so use it for fixtures and shared connections, not per-example state.

Calling helper methods on the topic

A helper's methods are also callable directly on the example topic. When an example block takes the topic (-> $_ { ... }), an unknown method on it resolves first to a let of that name, then to a method on any included helper:

class APIHelpers {
  method current-user() { ... }
}

configure-behave -> $config {
  $config.include(APIHelpers);
}

it 'reads the signed-in user', -> $_ {
  expect(.current-user).to.eq('alice');
}

A let always shadows a helper method of the same name, so a spec can override helper-provided values locally. Arguments pass straight through: .json-post($payload) calls the helper method with $payload.

Global hooks

Per-run hooks let you set up shared infrastructure without repeating it in every spec. Each phase composes with the per-group hooks declared inside spec files:

PhaseFires
before-allOnce per suite, before any example runs.
after-allOnce per suite, after every example has run.
before-eachBefore every example, before any group before-each.
after-eachAfter every example, after any group after-each.
around-eachWraps every example, outside the group around-each.
configure-behave -> $config {
  $config.before-all({ DB.migrate });
  $config.after-all({ DB.disconnect });

  $config.before-each({ DB.start-transaction });
  $config.after-each({ DB.rollback });

  $config.around-each(-> &next {
    my $start = now;
    next();
    note "example took {now - $start}s";
  });
}

Per-example phases (before-each, after-each, around-each) accept tag filters via named arguments:

$config.before-each({ Browser.launch }, :tag<feature>);
$config.after-each({  Browser.close  }, :tag<feature>);

Any unrecognised named argument is treated as a metadata filter: the hook only fires for examples whose effective metadata matches.

A global hook that throws is caught and reported as a warning so the run can continue.

Metadata filtering

$config.filter(:key<value>) keeps only the examples whose effective metadata (declared via :key<value> on describe, context, or it and inherited down the tree) matches. Pass a Bool true value ($config.filter(:db)) to require the key to be present and truthy.

configure-behave -> $config {
  $config.filter(:type<unit>);     # only :type<unit> examples
  $config.filter(:db);             # only examples with :db
  $config.exclude-filter(:flaky);  # skip every :flaky example
}

Multiple filter calls combine with AND: each pair must match. exclude-filter does the opposite: any matching pair drops the example. Config-level filters also AND with --tag/--exclude-tag/--example on the CLI, and with focus mode.

filter-run-when-matching

Inspired by RSpec's config.filter_run_when_matching :focus, this is a "soft" filter: it applies when at least one example matches, and is silently dropped otherwise so the rest of the run proceeds normally. Useful for a focus workflow: when you mark an example :focus, only it runs. When you remove the mark, the whole suite runs.

configure-behave -> $config {
  $config.filter-run-when-matching(:focus);
  $config.filter-run-when-matching(:wip);   # additional filter (AND with focus)
}

You can pass either a string key (treated as "metadata is truthy") or a pair (key => value). Multiple registrations stack with AND semantics, but each one is independently checked for the no-match short-circuit: a registration that matches nothing is dropped without affecting the others.

filter-run-when-matching interacts with the other filters:

Other filter activeBehavior
NoneThe filter applies if any example matches. Otherwise the entire suite runs.
--tag, --exclude-tag, --exampleThe filter is checked against the full spec tree. If it matches, it is added to the AND set with the CLI filters.
$config.filter (hard)Hard filter applies first. If filter-run-when-matching matches under that constraint, both apply.

Example: complete .behave

use BDD::Behave::Configuration;

class APIHelpers {
  method as-user($name) { ... }
}

configure-behave -> $config {
  # Defaults
  $config.format        = 'documentation';
  $config.order         = 'random';
  $config.fail-fast     = 1;
  $config.profile-limit = 10;

  # Default spec paths (used when none are passed on the CLI)
  $config.include-spec('specs/');

  # Helpers
  $config.include(APIHelpers);

  # Global setup / teardown
  $config.before-all({ DB.migrate });
  $config.after-all({  DB.disconnect });

  # Filters
  $config.exclude-filter(:flaky);

  # Honor a :focus marker when present
  $config.filter-run-when-matching(:focus);
}

With this file in your project root, behave (no arguments) loads it, applies your CLI flags on top, and runs specs/ in documentation format with full focus / flaky / DB management, no flags required.

BDD::Behave v0.9.4

Behavior driven development framework

Authors

  • Greg Donald

License

Artistic-2.0

Dependencies

Provides

  • BDD::Behave
  • BDD::Behave::Benchmark
  • BDD::Behave::Benchmark::Baseline
  • BDD::Behave::Benchmark::Format
  • BDD::Behave::Bisect
  • BDD::Behave::Colors
  • BDD::Behave::Configuration
  • BDD::Behave::Coverage
  • BDD::Behave::DSL
  • BDD::Behave::Diff
  • BDD::Behave::DocExtractor
  • BDD::Behave::DryRun
  • BDD::Behave::Expectation
  • BDD::Behave::Failure
  • BDD::Behave::FailureStore
  • BDD::Behave::Failures
  • BDD::Behave::Files
  • BDD::Behave::Formatter
  • BDD::Behave::Formatter::Documentation
  • BDD::Behave::Formatter::HTML
  • BDD::Behave::Formatter::JSON
  • BDD::Behave::Formatter::JUnit
  • BDD::Behave::Formatter::JsonEvents
  • BDD::Behave::Formatter::Progress
  • BDD::Behave::Formatter::Registry
  • BDD::Behave::Formatter::TAP
  • BDD::Behave::Formatter::Tree
  • BDD::Behave::LetRuntime
  • BDD::Behave::Matcher
  • BDD::Behave::Matcher::Async
  • BDD::Behave::Matcher::Boolean
  • BDD::Behave::Matcher::Change
  • BDD::Behave::Matcher::Collection
  • BDD::Behave::Matcher::Core
  • BDD::Behave::Matcher::Custom
  • BDD::Behave::Matcher::Exception
  • BDD::Behave::Matcher::Numeric
  • BDD::Behave::Matcher::String
  • BDD::Behave::Matcher::Type
  • BDD::Behave::Mock::Allow
  • BDD::Behave::Mock::ArgMatcher
  • BDD::Behave::Mock::Double
  • BDD::Behave::Mock::HaveReceived
  • BDD::Behave::Mock::Spy
  • BDD::Behave::Mock::Stub
  • BDD::Behave::Parallel
  • BDD::Behave::Parallel::Distribution
  • BDD::Behave::Parallel::EventStream
  • BDD::Behave::Parallel::Manifest
  • BDD::Behave::Parallel::Queue
  • BDD::Behave::Parallel::WorkerPool
  • BDD::Behave::Runner
  • BDD::Behave::SharedContexts
  • BDD::Behave::SharedExamples
  • BDD::Behave::Slang
  • BDD::Behave::SpecLoader
  • BDD::Behave::SpecRegistry
  • BDD::Behave::SpecTree
  • BDD::Behave::SpecTree::Core
  • BDD::Behave::SpecTree::Example
  • BDD::Behave::SpecTree::ExampleGroup
  • BDD::Behave::SpecTree::Suite
  • BDD::Behave::Time
  • BDD::Behave::TypeName
  • BDD::Behave::Version
  • BDD::Behave::Watch
  • BDD::Behave::Watch::Session
  • BDD::Behave::Watch::SmartSelector
  • BDD::Behave::Watch::UI
  • BDD::Behave::Watch::Watcher
  • BDD::Behave::Worker

The Camelia image is copyright 2009 by Larry Wall. "Raku" is trademark of the Yet Another Society. All rights reserved.