Removing the vertical examples support
This commit is contained in:
parent
e0a1437908
commit
6730b428ed
|
@ -4,8 +4,11 @@ Changelog
|
||||||
Unreleased
|
Unreleased
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
This release introduces breaking changes in order to be more in line with the official gherkin specification.
|
||||||
|
|
||||||
- Cleanup of the documentation and tests related to parametrization (elchupanebrej)
|
- Cleanup of the documentation and tests related to parametrization (elchupanebrej)
|
||||||
- Removed feature level examples for gherkin compatibility (olegpidsadnyi)
|
- Removed feature level examples for the gherkin compatibility (olegpidsadnyi)
|
||||||
|
- Removed vertical examples for the gherkin compatibility (olegpidsadnyi)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
81
README.rst
81
README.rst
|
@ -522,63 +522,6 @@ Example:
|
||||||
| start | eat | left |
|
| start | eat | left |
|
||||||
| 12 | 5 | 7 |
|
| 12 | 5 | 7 |
|
||||||
|
|
||||||
pytest-bdd feature file format also supports example tables in different way:
|
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: gherkin
|
|
||||||
|
|
||||||
Feature: Scenario outlines
|
|
||||||
Scenario Outline: Outlined given, when, then
|
|
||||||
Given there are <start> cucumbers
|
|
||||||
When I eat <eat> cucumbers
|
|
||||||
Then I should have <left> cucumbers
|
|
||||||
|
|
||||||
Examples: Vertical
|
|
||||||
| start | 12 | 2 |
|
|
||||||
| eat | 5 | 1 |
|
|
||||||
| left | 7 | 1 |
|
|
||||||
|
|
||||||
This form allows to have tables with lots of columns keeping the maximum text width predictable without significant
|
|
||||||
readability change.
|
|
||||||
|
|
||||||
The code will look like:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from pytest_bdd import given, when, then, scenario, parsers
|
|
||||||
|
|
||||||
|
|
||||||
@scenario(
|
|
||||||
"outline.feature",
|
|
||||||
"Outlined given, when, then",
|
|
||||||
)
|
|
||||||
def test_outlined():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@given(parsers.parse("there are {start:d} cucumbers", target_fixture="start_cucumbers"))
|
|
||||||
def start_cucumbers(start):
|
|
||||||
assert isinstance(start, int)
|
|
||||||
return dict(start=start)
|
|
||||||
|
|
||||||
|
|
||||||
@when(parsers.parse("I eat {eat:g} cucumbers"))
|
|
||||||
def eat_cucumbers(start_cucumbers, eat):
|
|
||||||
assert isinstance(eat, float)
|
|
||||||
start_cucumbers["eat"] = eat
|
|
||||||
|
|
||||||
|
|
||||||
@then(parsers.parse("I should have {left} cucumbers"))
|
|
||||||
def should_have_left_cucumbers(start_cucumbers, start, eat, left):
|
|
||||||
assert isinstance(left, str)
|
|
||||||
assert start - eat == int(left)
|
|
||||||
assert start_cucumbers["start"] == start
|
|
||||||
assert start_cucumbers["eat"] == eat
|
|
||||||
|
|
||||||
Example code also shows possibility to pass example converters which may be useful if you need parameter types
|
|
||||||
different than strings.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Organizing your scenarios
|
Organizing your scenarios
|
||||||
-------------------------
|
-------------------------
|
||||||
|
@ -1056,6 +999,30 @@ As as side effect, the tool will validate the files for format errors, also some
|
||||||
ordering of the types of the steps.
|
ordering of the types of the steps.
|
||||||
|
|
||||||
|
|
||||||
|
.. _Migration from 5.x.x:
|
||||||
|
|
||||||
|
Migration of your tests from versions 5.x.x
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
The primary focus of the pytest-bdd is the compatibility with the latest gherkin developments
|
||||||
|
e.g. multiple scenario outline example tables with tags support etc.
|
||||||
|
|
||||||
|
In order to provide the best compatibility it is best to support the features described in the official
|
||||||
|
gherkin reference. This means deprecation of some non-standard features that were implemented in pytest-bdd.
|
||||||
|
|
||||||
|
|
||||||
|
Removal of the feature examples
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
The example tables on the feature level are no longer supported. The tests should be parametrized with the example tables
|
||||||
|
on the scenario level.
|
||||||
|
|
||||||
|
|
||||||
|
Removal of the vertical examples
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
Vertical example tables are no longer supported since the official gherkin doesn't support them.
|
||||||
|
The example tables should have horizontal orientation.
|
||||||
|
|
||||||
|
|
||||||
.. _Migration from 4.x.x:
|
.. _Migration from 4.x.x:
|
||||||
|
|
||||||
Migration of your tests from versions 4.x.x
|
Migration of your tests from versions 4.x.x
|
||||||
|
|
|
@ -12,7 +12,6 @@ COMMENT_RE = re.compile(r"(^|(?<=\s))#")
|
||||||
STEP_PREFIXES = [
|
STEP_PREFIXES = [
|
||||||
("Feature: ", types.FEATURE),
|
("Feature: ", types.FEATURE),
|
||||||
("Scenario Outline: ", types.SCENARIO_OUTLINE),
|
("Scenario Outline: ", types.SCENARIO_OUTLINE),
|
||||||
("Examples: Vertical", types.EXAMPLES_VERTICAL),
|
|
||||||
("Examples:", types.EXAMPLES),
|
("Examples:", types.EXAMPLES),
|
||||||
("Scenario: ", types.SCENARIO),
|
("Scenario: ", types.SCENARIO),
|
||||||
("Background:", types.BACKGROUND),
|
("Background:", types.BACKGROUND),
|
||||||
|
@ -157,26 +156,11 @@ def parse_feature(basedir: str, filename: str, encoding: str = "utf-8") -> "Feat
|
||||||
elif mode == types.EXAMPLES:
|
elif mode == types.EXAMPLES:
|
||||||
mode = types.EXAMPLES_HEADERS
|
mode = types.EXAMPLES_HEADERS
|
||||||
scenario.examples.line_number = line_number
|
scenario.examples.line_number = line_number
|
||||||
elif mode == types.EXAMPLES_VERTICAL:
|
|
||||||
mode = types.EXAMPLE_LINE_VERTICAL
|
|
||||||
scenario.examples.line_number = line_number
|
|
||||||
elif mode == types.EXAMPLES_HEADERS:
|
elif mode == types.EXAMPLES_HEADERS:
|
||||||
scenario.examples.set_param_names([l for l in split_line(parsed_line) if l])
|
scenario.examples.set_param_names([l for l in split_line(parsed_line) if l])
|
||||||
mode = types.EXAMPLE_LINE
|
mode = types.EXAMPLE_LINE
|
||||||
elif mode == types.EXAMPLE_LINE:
|
elif mode == types.EXAMPLE_LINE:
|
||||||
scenario.examples.add_example([l for l in split_line(stripped_line)])
|
scenario.examples.add_example([l for l in split_line(stripped_line)])
|
||||||
elif mode == types.EXAMPLE_LINE_VERTICAL:
|
|
||||||
param_line_parts = [l for l in split_line(stripped_line)]
|
|
||||||
try:
|
|
||||||
scenario.examples.add_example_row(param_line_parts[0], param_line_parts[1:])
|
|
||||||
except exceptions.ExamplesNotValidError as exc:
|
|
||||||
raise exceptions.FeatureError(
|
|
||||||
f"Scenario has not valid examples. {exc.args[0]}",
|
|
||||||
line_number,
|
|
||||||
clean_line,
|
|
||||||
filename,
|
|
||||||
)
|
|
||||||
|
|
||||||
elif mode and mode not in (types.FEATURE, types.TAG):
|
elif mode and mode not in (types.FEATURE, types.TAG):
|
||||||
step = Step(name=parsed_line, type=mode, indent=line_indent, line_number=line_number, keyword=keyword)
|
step = Step(name=parsed_line, type=mode, indent=line_indent, line_number=line_number, keyword=keyword)
|
||||||
if feature.background and not scenario:
|
if feature.background and not scenario:
|
||||||
|
@ -383,7 +367,6 @@ class Examples:
|
||||||
"""Initialize examples instance."""
|
"""Initialize examples instance."""
|
||||||
self.example_params = []
|
self.example_params = []
|
||||||
self.examples = []
|
self.examples = []
|
||||||
self.vertical_examples = []
|
|
||||||
self.line_number = None
|
self.line_number = None
|
||||||
self.name = None
|
self.name = None
|
||||||
|
|
||||||
|
@ -412,17 +395,8 @@ class Examples:
|
||||||
f"""Example rows should contain unique parameters. "{param}" appeared more than once"""
|
f"""Example rows should contain unique parameters. "{param}" appeared more than once"""
|
||||||
)
|
)
|
||||||
self.example_params.append(param)
|
self.example_params.append(param)
|
||||||
self.vertical_examples.append(values)
|
|
||||||
|
|
||||||
def as_contexts(self) -> typing.Iterable[typing.Dict[str, typing.Any]]:
|
def as_contexts(self) -> typing.Iterable[typing.Dict[str, typing.Any]]:
|
||||||
param_count = len(self.example_params)
|
|
||||||
if self.vertical_examples and not self.examples:
|
|
||||||
for value_index in range(len(self.vertical_examples[0])):
|
|
||||||
example = []
|
|
||||||
for param_index in range(param_count):
|
|
||||||
example.append(self.vertical_examples[param_index][value_index])
|
|
||||||
self.examples.append(example)
|
|
||||||
|
|
||||||
if not self.examples:
|
if not self.examples:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -430,12 +404,11 @@ class Examples:
|
||||||
|
|
||||||
for row in rows:
|
for row in rows:
|
||||||
assert len(header) == len(row)
|
assert len(header) == len(row)
|
||||||
|
|
||||||
yield dict(zip(header, row))
|
yield dict(zip(header, row))
|
||||||
|
|
||||||
def __bool__(self):
|
def __bool__(self):
|
||||||
"""Bool comparison."""
|
"""Bool comparison."""
|
||||||
return bool(self.vertical_examples or self.examples)
|
return bool(self.examples)
|
||||||
|
|
||||||
|
|
||||||
def get_tags(line):
|
def get_tags(line):
|
||||||
|
|
|
@ -3,10 +3,8 @@
|
||||||
FEATURE = "feature"
|
FEATURE = "feature"
|
||||||
SCENARIO_OUTLINE = "scenario outline"
|
SCENARIO_OUTLINE = "scenario outline"
|
||||||
EXAMPLES = "examples"
|
EXAMPLES = "examples"
|
||||||
EXAMPLES_VERTICAL = "examples vertical"
|
|
||||||
EXAMPLES_HEADERS = "example headers"
|
EXAMPLES_HEADERS = "example headers"
|
||||||
EXAMPLE_LINE = "example line"
|
EXAMPLE_LINE = "example line"
|
||||||
EXAMPLE_LINE_VERTICAL = "example line vertical"
|
|
||||||
SCENARIO = "scenario"
|
SCENARIO = "scenario"
|
||||||
BACKGROUND = "background"
|
BACKGROUND = "background"
|
||||||
GIVEN = "given"
|
GIVEN = "given"
|
||||||
|
|
|
@ -122,46 +122,6 @@ def test_wrongly_outlined(testdir):
|
||||||
result.stdout.fnmatch_lines("*should match set of example values [[]'eat', 'left', 'start', 'unknown_param'[]].*")
|
result.stdout.fnmatch_lines("*should match set of example values [[]'eat', 'left', 'start', 'unknown_param'[]].*")
|
||||||
|
|
||||||
|
|
||||||
def test_wrong_vertical_examples_scenario(testdir):
|
|
||||||
"""Test parametrized scenario vertical example table has wrong format."""
|
|
||||||
testdir.makefile(
|
|
||||||
".feature",
|
|
||||||
outline=textwrap.dedent(
|
|
||||||
"""\
|
|
||||||
Feature: Outline
|
|
||||||
Scenario Outline: Outlined with wrong vertical example table
|
|
||||||
Given there are <start> cucumbers
|
|
||||||
When I eat <eat> cucumbers
|
|
||||||
Then I should have <left> cucumbers
|
|
||||||
|
|
||||||
Examples: Vertical
|
|
||||||
| start | 12 | 2 |
|
|
||||||
| start | 10 | 1 |
|
|
||||||
| left | 7 | 1 |
|
|
||||||
"""
|
|
||||||
),
|
|
||||||
)
|
|
||||||
testdir.makeconftest(textwrap.dedent(STEPS))
|
|
||||||
|
|
||||||
testdir.makepyfile(
|
|
||||||
textwrap.dedent(
|
|
||||||
"""\
|
|
||||||
from pytest_bdd import scenario
|
|
||||||
|
|
||||||
@scenario("outline.feature", "Outlined with wrong vertical example table")
|
|
||||||
def test_outline(request):
|
|
||||||
pass
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
)
|
|
||||||
result = testdir.runpytest()
|
|
||||||
assert_outcomes(result, errors=1)
|
|
||||||
result.stdout.fnmatch_lines(
|
|
||||||
"*Scenario has not valid examples. Example rows should contain unique parameters. "
|
|
||||||
'"start" appeared more than once.*'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_outlined_with_other_fixtures(testdir):
|
def test_outlined_with_other_fixtures(testdir):
|
||||||
"""Test outlined scenario also using other parametrized fixture."""
|
"""Test outlined scenario also using other parametrized fixture."""
|
||||||
testdir.makefile(
|
testdir.makefile(
|
||||||
|
@ -211,54 +171,6 @@ def test_outlined_with_other_fixtures(testdir):
|
||||||
result.assert_outcomes(passed=6)
|
result.assert_outcomes(passed=6)
|
||||||
|
|
||||||
|
|
||||||
def test_vertical_example(testdir):
|
|
||||||
"""Test outlined scenario with vertical examples table."""
|
|
||||||
testdir.makefile(
|
|
||||||
".feature",
|
|
||||||
outline=textwrap.dedent(
|
|
||||||
"""\
|
|
||||||
Feature: Outline
|
|
||||||
Scenario Outline: Outlined with vertical example table
|
|
||||||
Given there are <start> cucumbers
|
|
||||||
When I eat <eat> cucumbers
|
|
||||||
Then I should have <left> cucumbers
|
|
||||||
|
|
||||||
Examples: Vertical
|
|
||||||
| start | 12 | 2 |
|
|
||||||
| eat | 5 | 1 |
|
|
||||||
| left | 7 | 1 |
|
|
||||||
|
|
||||||
"""
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
testdir.makeconftest(textwrap.dedent(STEPS))
|
|
||||||
|
|
||||||
testdir.makepyfile(
|
|
||||||
textwrap.dedent(
|
|
||||||
"""\
|
|
||||||
from pytest_bdd import scenario
|
|
||||||
|
|
||||||
@scenario(
|
|
||||||
"outline.feature",
|
|
||||||
"Outlined with vertical example table",
|
|
||||||
)
|
|
||||||
def test_outline():
|
|
||||||
pass
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
)
|
|
||||||
result = testdir.runpytest("-s")
|
|
||||||
result.assert_outcomes(passed=2)
|
|
||||||
parametrizations = collect_dumped_objects(result)
|
|
||||||
# fmt: off
|
|
||||||
assert parametrizations == [
|
|
||||||
12, 5.0, "7",
|
|
||||||
2, 1.0, "1",
|
|
||||||
]
|
|
||||||
# fmt: on
|
|
||||||
|
|
||||||
|
|
||||||
def test_outline_with_escaped_pipes(testdir):
|
def test_outline_with_escaped_pipes(testdir):
|
||||||
"""Test parametrized feature example table with escaped pipe characters in input."""
|
"""Test parametrized feature example table with escaped pipe characters in input."""
|
||||||
testdir.makefile(
|
testdir.makefile(
|
||||||
|
|
|
@ -61,40 +61,3 @@ def test_scenario_with_empty_example_values(testdir):
|
||||||
result = testdir.runpytest("-s")
|
result = testdir.runpytest("-s")
|
||||||
result.assert_outcomes(passed=1)
|
result.assert_outcomes(passed=1)
|
||||||
assert collect_dumped_objects(result) == ["#", "", ""]
|
assert collect_dumped_objects(result) == ["#", "", ""]
|
||||||
|
|
||||||
|
|
||||||
def test_scenario_with_empty_example_values_vertical(testdir):
|
|
||||||
testdir.makefile(
|
|
||||||
".feature",
|
|
||||||
outline=textwrap.dedent(
|
|
||||||
"""\
|
|
||||||
Feature: Outline
|
|
||||||
Scenario Outline: Outlined with empty example values vertical
|
|
||||||
Given there are <start> cucumbers
|
|
||||||
When I eat <eat> cucumbers
|
|
||||||
Then I should have <left> cucumbers
|
|
||||||
|
|
||||||
Examples: Vertical
|
|
||||||
| start | # |
|
|
||||||
| eat | |
|
|
||||||
| left | |
|
|
||||||
"""
|
|
||||||
),
|
|
||||||
)
|
|
||||||
testdir.makeconftest(textwrap.dedent(STEPS))
|
|
||||||
|
|
||||||
testdir.makepyfile(
|
|
||||||
textwrap.dedent(
|
|
||||||
"""\
|
|
||||||
from pytest_bdd.utils import dump_obj
|
|
||||||
from pytest_bdd import scenario
|
|
||||||
|
|
||||||
@scenario("outline.feature", "Outlined with empty example values vertical")
|
|
||||||
def test_outline():
|
|
||||||
pass
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
)
|
|
||||||
result = testdir.runpytest("-s")
|
|
||||||
result.assert_outcomes(passed=1)
|
|
||||||
assert collect_dumped_objects(result) == ["#", "", ""]
|
|
||||||
|
|
Loading…
Reference in New Issue