このエントリでは、
Behaveで、現在テスト中のステップを把握する方法を記載します。

シナリオ下のステップ一覧表示

シナリオ下のステップは、次のようなコードで一覧表示することができます。

# -- FILE: sample.feature
Feature: sample feature
    Scenario: sample scenario
        Given sample step
        When sample step
        Then sample step
# -- FILE: steps/sample.py
from behave import *

@step('sample step')
def step_impl(context):
    print("\n".join([f'[{e.status.name}] {e.step_type} {e.name}' for e in context.scenario.all_steps]))
    print("\n")

実行結果

$ behave --no-capture sample.feature
Feature: sample feature # sample.feature:2

  Scenario: sample scenario  # sample.feature:3
    Given sample step        # steps/sample.py:4
[untested] given sample step
[untested] when sample step
[untested] then sample step

    Given sample step        # steps/sample.py:4 0.000s
    When sample step         # steps/sample.py:4
[passed] given sample step
[untested] when sample step
[untested] then sample step

    When sample step         # steps/sample.py:4 0.000s
    Then sample step         # steps/sample.py:4
[passed] given sample step
[passed] when sample step
[untested] then sample step

    Then sample step         # steps/sample.py:4 0.000s

1 feature passed, 0 failed, 0 skipped
1 scenario passed, 0 failed, 0 skipped
3 steps passed, 0 failed, 0 skipped, 0 undefined
Took 0m0.000s

現在テスト中のステップ把握

シナリオ下のステップ一覧の内、untestedの先頭が現在テスト中のステップなので、
次のようなコードで把握することができる。

# -- FILE: steps/sample.py
from behave import *
import behave.model

@step('sample step')
def step_impl(context):
    current_step = [e for e in context.scenario.all_steps if e.status == behave.model.Status.untested][0]
    print(f'{current_step.step_type} {current_step.name}')
    print("\n")

実行結果

$ behave --no-capture sample.feature
Feature: sample feature # sample.feature:2

  Scenario: sample scenario  # sample.feature:3
    Given sample step        # steps/sample.py:5
given sample step

    Given sample step        # steps/sample.py:5 0.000s
    When sample step         # steps/sample.py:5
when sample step

    When sample step         # steps/sample.py:5 0.000s
    Then sample step         # steps/sample.py:5
then sample step

    Then sample step         # steps/sample.py:5 0.000s

1 feature passed, 0 failed, 0 skipped
1 scenario passed, 0 failed, 0 skipped
3 steps passed, 0 failed, 0 skipped, 0 undefined
Took 0m0.000s

応用例

現在テスト中のステップが把握できて何が嬉しいのか? ですが、
例えば、テストのステップでデータベースにレコードを追加する操作が必要な場合、
「Givenでは前提条件としてデータを準備する」
「Whenではデータを追加する操作が成功するかを確認するために操作する」
とステップタイプで意味が変わる場合があると思います。

Given/Whenのデコレータごと2つ関数を定義しても良いですが、
次のようにstep_typeで、upsert/insertを切り替えた方がスッキリ書ける時もあると思います。

# -- FILE: steps/sample.py
from behave import *
import behave.model

@step('sample step')
def step_impl(context):
    current_step = [e for e in context.scenario.all_steps if e.status == behave.model.Status.untested][0]
    if current_step.step_type == "given":
        print("upsert\n") # upsert処理を実行する
    elif current_step.step_type == "when":
        print("insert\n") # insert処理を実行する
    else:
        assert False, "not implemented"

以上。