I'm not sure that I understood your question correctly, but aren't you trying to achieve something like this?
Before each When
step we are checking if next Then
step contains "is raised"
.
If so, we mark this When
step as "expected to fail".
During needed When
step execution we check corresponding flag and use pytest.raises
method to handle it.
For first two steps I use pytest_bdd_before_step hook and request
fixture. And for 3rd I just define some function handle_step
right in test module. Of course you should move it somewhere else. This function requires step
(which is just some defined function with your code) and request.node.step.expect_failure
to decide whether to use pytest.raises
or not.
As an option you can use callable fixture (requesting request
fixture) to store this function and avoid using request.node.step.expect_failure
in such keywords.
Also you can add functionality to define allowed exceptions and so on.
test_exception.py
import pytest
from pytest_bdd import then, when, scenario
@scenario("exc.feature", "Test expecting correct exception")
def test_1():
pass
def handle_step(step, expect_failure):
if expect_failure:
pytest.raises(Exception, step)
else:
step()
@when("I perform an operation")
def operation_calling_exception(request):
def step():
# some code that causes an exception
print(1 / 0)
handle_step(step, request.node.step.expect_failure)
@then('an exception is raised')
def ex_raised():
pass
exc.feature
Feature: Target fixture
Scenario: Test expecting correct exception
When I perform an operation
Then an exception is raised
conftest.py
def pytest_bdd_before_step(request, feature, scenario, step, step_func):
# set default `expect_failure` for step
step.expect_failure = False
# make step available from request fixture
request.node.step = step
# Only for `When` keywords
if step.keyword == "When":
# get current step position in scenario
step_position = scenario.steps.index(step)
# get following `Then` step
then_step = next((s for s in scenario.steps[step_position:] if s.keyword == "Then"), None)
if "is raised" in then_step.name:
step.expect_failure = True