Skillversitas

Step Matchers

A step matcher decides whether a parsed Gherkin step should invoke your function. Behave matches in a fixed order, tries kind-specific pools first, and refuses ambiguity. Knowing the exact resolution rules prevents the two classic surprises: a step suddenly running a different implementation, and _framework_ errors about parse variants.

Matching Variants and Pools

For each step behaves has four registered name variants of the text: the plain text, the text with each parameter replaced by a generic placeholder, the text with the actual values, and a regular-expression form. It matches in this order and uses the first registered pattern: exact text, then its four variants. Also, When and Then patterns are (mostly) interchangeable at match time — a @when-registered pattern matching a Given-keyword step is normally a usage review issue, not an error. Matching is "first come, first match" — no selection heuristics, no best-match scoring.

from behave import when

@when("the user searches")
def plain_search(context): ...

@when("the user searches for {term}")
def param_search(context, term): ...

Here a feature step "the user searches for cheese" matches only param_search; the literal pattern does not fit.

Built-in Simple Matcher

The default core matcher supports small syntax bits:

@given('the "{thing}" exists')
def exists(context, thing):
    context.thing = thing

This matches Given the "printer" exists with thing="printer". The core matcher supports tiny grammar consequents but is limited; real projects switch to the parse-based matcher, which behave enables by default.

Parse-Based Matching (Default)

@given("a cart with {count:d} items")
def items_count(context, count):
    context.count = count

Placeholders convert the captured substring to a typed value. Type letters: :d, :f, :w (word, default), :s, :e (anything). The names come from the parse library and are covered deeper in the step-parameters chapter.

Regex Matching — use_step_matcher("re")

For unmatched control, swap the matcher:

from behave import given, when, then
from behave import use_step_matcher, step

use_step_matcher("re")

@given(r"the user (?P<name>\S+)")
def user_named(context, name):
    context.name = name

@then(r"password length \s*equals (?P<n>\d+)")
def pw_len(context, n):
    assert len(context.password) == int(n)

use_step_matcher("parse")

This restoration matters: use_step_matcher("re") changes the meaning of every pattern registered after it in the module (and any module imported afterwards). Restore with use_step_matcher("parse") as soon as regex needs end. Literal spaces are not literal in regex land — the pattern "the {thing} is" behaves differently per matcher.

The Universal step Decorator

The wildcard @step register regardless of keyword — practical for phrases that occur as Given, When, and Then:

from behave import step

@step("a usable session exists")
def session(context):
    context.session = ensure_session()

Choosing Patterns Wisely

  • Prefer parse patterns (plain quotes, colon types) — they keep the snippet output cleaned and errors precise.
  • Keep patterns distinct; near-identical text with different topics causes accidental shadowing as the suite grows.
  • Escape special characters you need literally in regex mode.
  • Never rely on pattern definition order; regularization comes from registration, not the file layout.

Summary

Behave picks between pool variants by trying pattern alternatives in fixed order, uses the parse library for typed placeholders by default, and switches to raw regex via use_step_matcher("re") when needed. Ambiguity is an error you must design away rather than a match tie the runner resolves for you.