Sub-step Execution¶
Execute Gherkin sub-steps from within a step with Scenario Outline variable substitution and guaranteed state isolation.
Behave’s context.execute_steps() lets you compose steps from other
steps, but it has two rough edges:
context.tableandcontext.textare mutated by the sub-steps and not restored, leaking state into the parent step.Scenario Outline placeholders (
<name>) are not substituted, so sub-steps can’t reference the current outline row’s values.
behave_kit.run_steps() wraps execute_steps to fix both.
run_steps¶
- behave_kit.context.substeps.run_steps(context: Context, steps: str) None[source]
Execute Gherkin sub-steps with state isolation.
Wraps
context.execute_steps()with:Scenario Outline
<placeholder>substitution fromcontext.active_outline.Guaranteed restoration of
context.tableandcontext.text.
- Parameters:
context – The Behave context for the current scenario.
steps – Gherkin step text to execute. Must be a string containing one or more step definitions with keywords (Given/When/Then/And/But).
- Raises:
SubStepError – If called outside a feature context.
AssertionError – If any sub-step fails (propagated from Behave).
Basic usage¶
from behave_kit import run_steps
@when("I complete the checkout flow")
def step_impl(context):
run_steps(context, '''
Given I have items in my cart
When I enter shipping info
Then I should see the order confirmation
''')
The sub-steps are executed in order. If any sub-step fails, Behave
raises an AssertionError describing which step failed, and the
exception propagates out of run_steps.
Scenario Outline substitution¶
When the calling scenario is part of a Scenario Outline,
run_steps substitutes <placeholder> patterns with the values
from context.active_outline:
Scenario Outline: Checkout in <city>
When I complete the checkout flow for "<city>"
Then the shipping address should be in "<city>"
Examples:
| city |
| Berlin |
| Paris |
@when('I complete the checkout flow for "{city}"')
def step_impl(context, city):
run_steps(context, '''
Given I have items in my cart
When I enter shipping info for "<city>"
Then I should see the order confirmation
''')
The <city> placeholder in the sub-step text is replaced with the
current outline row’s value (e.g. Berlin) before the sub-steps are
executed.
State isolation¶
run_steps saves and restores context.table and context.text
around the sub-step execution, so the parent step’s values are
preserved:
@when("I run a composite step")
def step_impl(context):
# context.table is set by the parent step.
original_table = context.table
run_steps(context, '''
Given a sub-step that uses a table
''')
# The sub-step's table (if any) does not leak out.
assert context.table is original_table
Validation¶
run_steps validates its inputs before delegating to Behave:
stepsmust be a non-empty string (after stripping whitespace). Empty or whitespace-only input raisesAssertionError.context.active_outlinemust be adictwhen present. A list or string raisesAssertionErrorwith a clear message.context.execute_stepsmust be callable. If it isn’t (e.g.run_stepsis called outside a Behave context),SubStepErroris raised.
SubStepError¶
- exception behave_kit.context.substeps.SubStepError(message: str, *, cause: BaseException | None = None, suggestion: str | None = None)[source]
Bases:
BehaveKitErrorRaised when sub-step execution fails or is used outside a feature context.
Raised when sub-step execution fails or run_steps is used outside
a feature context.
Example error:
behave_kit.context.substeps.SubStepError: run_steps() requires a
Behave context with execute_steps(); called outside a feature.