Step arguments are no longer fixtures

This commit is contained in:
Oleg Pidsadnyi 2022-01-15 20:20:19 +01:00
parent 6730b428ed
commit 7cd7b40df3
8 changed files with 40 additions and 136 deletions

View File

@ -9,6 +9,7 @@ This release introduces breaking changes in order to be more in line with the of
- Cleanup of the documentation and tests related to parametrization (elchupanebrej)
- Removed feature level examples for the gherkin compatibility (olegpidsadnyi)
- Removed vertical examples for the gherkin compatibility (olegpidsadnyi)
- Step arguments are no longer fixtures (olegpidsadnyi)

View File

@ -1023,6 +1023,12 @@ Vertical example tables are no longer supported since the official gherkin doesn
The example tables should have horizontal orientation.
Step arguments are no longer fixtures
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Step parsed arguments conflicted with the fixtures. Now they no longer define fixture.
If the fixture has to be defined by the step the target_fixture param should be used.
.. _Migration from 4.x.x:
Migration of your tests from versions 4.x.x

View File

@ -44,7 +44,7 @@ def parse_line(line):
"""
for prefix, _ in STEP_PREFIXES:
if line.startswith(prefix):
return prefix.strip(), line[len(prefix) :].strip()
return prefix.strip(), line[len(prefix):].strip()
return "", line

View File

@ -44,14 +44,6 @@ def find_argumented_step_fixture_name(name, type_, fixturemanager, request=None)
if not match:
continue
# TODO: maybe `converters` should be part of the SterParser.__init__(),
# and used by StepParser.parse_arguments() method
converters = getattr(fixturedef.func, "converters", {})
for arg, value in parser.parse_arguments(name).items():
if arg in converters:
value = converters[arg](value)
if request:
inject_fixture(request, arg, value)
parser_name = get_step_fixture_name(parser.name, type_)
if request:
try:
@ -105,7 +97,20 @@ def _execute_step_function(request, scenario, step, step_func):
kw["step_func_args"] = {}
try:
# Get the step argument values.
kwargs = {arg: request.getfixturevalue(arg) for arg in get_args(step_func)}
converters = getattr(step_func, "converters", {})
kwargs = {}
parser = getattr(step_func, "parser", None)
if parser is not None:
for arg, value in parser.parse_arguments(step.name).items():
if arg in converters:
value = converters[arg](value)
kwargs[arg] = value
kwargs = {
arg: kwargs[arg] if arg in kwargs else request.getfixturevalue(arg)
for arg in get_args(step_func)
}
kw["step_func_args"] = kwargs
request.config.hook.pytest_bdd_before_step_call(**kw)

View File

@ -1,104 +0,0 @@
import textwrap
def test_arg_fixture_mix(testdir):
subdir = testdir.mkpydir("arg_fixture_mix")
subdir.join("test_a.py").write(
textwrap.dedent(
"""\
import re
import pytest
from pytest_bdd import scenario, given, then, parsers
@pytest.fixture
def foo():
return "fine"
@scenario(
'arg_and_fixture_mix.feature',
'Use the step argument with the same name as fixture of another test',
)
def test_args():
pass
@given(parsers.parse('foo is "{foo}"'))
def foo1(foo):
pass
@then(parsers.parse('foo should be "{foo_value}"'))
def foo_should_be(foo, foo_value):
assert foo == foo_value
@scenario(
'arg_and_fixture_mix.feature',
'Everything is fine',
)
def test_bar():
pass
@given('it is all fine')
def fine():
return "fine"
@then('foo should be fine')
def foo_should_be_fine(foo):
assert foo == "fine"
"""
)
)
subdir.join("test_b.py").write(
textwrap.dedent(
"""\
import re
import pytest
from pytest_bdd import scenario, given, then
@scenario(
'arg_and_fixture_mix.feature',
'Everything is fine',
)
def test_args():
pass
@pytest.fixture
def foo():
return "fine"
@given('it is all fine')
def fine():
return "fine"
@then('foo should be fine')
def foo_should_be(foo):
assert foo == "fine"
def test_bar(foo):
assert foo == 'fine'
"""
)
)
subdir.join("arg_and_fixture_mix.feature").write(
"""
Feature: Arg and fixture mix
Scenario: Use the step argument with the same name as fixture of another test
Given foo is "Hello"
Then foo should be "Hello"
Scenario: Everything is fine
Given it is all fine
Then foo should be fine
"""
)
result = testdir.runpytest("-k arg_fixture_mix")
result.assert_outcomes(passed=4)

View File

@ -87,14 +87,14 @@ def test_multiline(testdir, feature_text, expected_text):
assert request.getfixturevalue("text") == expected_text
@given(parsers.parse("I have a step with:\\n{{text}}"), target_fixture="i_have_text")
@given(parsers.parse("I have a step with:\\n{{text}}"), target_fixture="text")
def i_have_text(text):
return text
@then("the text should be parsed with correct indentation")
def text_should_be_correct(i_have_text, text):
assert i_have_text == text == expected_text
def text_should_be_correct(text):
assert text == expected_text
""".format(
expected_text=expected_text.encode("unicode_escape").decode("utf-8"),
@ -137,14 +137,14 @@ def test_multiline_wrong_indent(testdir):
pass
@given(parsers.parse("I have a step with:\\n{{text}}"))
@given(parsers.parse("I have a step with:\\n{{text}}"), target_fixture="text")
def i_have_text(text):
return text
@then("the text should be parsed with correct indentation")
def text_should_be_correct(i_have_text, text):
assert i_have_text == text == expected_text
def text_should_be_correct(text):
assert text == expected_text
"""
)

View File

@ -9,27 +9,25 @@ from pytest_bdd import parsers, given, when, then
from pytest_bdd.utils import dump_obj
@given(parsers.parse("there are {start:d} cucumbers"), target_fixture="start_cucumbers")
def start_cucumbers(start):
@given(parsers.parse("there are {start:d} cucumbers"), target_fixture="cucumbers")
def given_cucumbers(start):
assert isinstance(start, int)
dump_obj(start)
return {"start": start}
@when(parsers.parse("I eat {eat:g} cucumbers"))
def eat_cucumbers(start_cucumbers, eat):
def eat_cucumbers(cucumbers, eat):
assert isinstance(eat, float)
dump_obj(eat)
start_cucumbers["eat"] = eat
cucumbers["eat"] = eat
@then(parsers.parse("I should have {left} cucumbers"))
def should_have_left_cucumbers(start_cucumbers, start, eat, left):
def should_have_left_cucumbers(cucumbers, left):
assert isinstance(left, str)
dump_obj(left)
assert start - eat == int(left)
assert start_cucumbers["start"] == start
assert start_cucumbers["eat"] == eat
assert cucumbers["start"] - cucumbers["eat"] == int(left)
"""

View File

@ -76,24 +76,22 @@ def test_step_trace(testdir):
def a_failing_step():
raise Exception('Error')
@given(parsers.parse('there are {start:d} cucumbers'), target_fixture="start_cucumbers")
def start_cucumbers(start):
@given(parsers.parse('there are {start:d} cucumbers'), target_fixture="cucumbers")
def given_cucumbers(start):
assert isinstance(start, int)
return {"start": start}
@when(parsers.parse('I eat {eat:g} cucumbers'))
def eat_cucumbers(start_cucumbers, eat):
def eat_cucumbers(cucumbers, eat):
assert isinstance(eat, float)
start_cucumbers['eat'] = eat
cucumbers['eat'] = eat
@then(parsers.parse('I should have {left} cucumbers'))
def should_have_left_cucumbers(start_cucumbers, start, eat, left):
def should_have_left_cucumbers(cucumbers, left):
assert isinstance(left, str)
assert start - eat == int(left)
assert start_cucumbers['start'] == start
assert start_cucumbers['eat'] == eat
assert cucumbers['start'] - cucumbers['eat'] == int(left)
scenarios('test.feature')