From d52dea9215981ab3b45dc0a8b29f7f1eb3122655 Mon Sep 17 00:00:00 2001 From: Oleg Pidsadnyi Date: Wed, 12 Jan 2022 15:54:02 +0100 Subject: [PATCH] Preparing the scenario for multiple example tables --- pytest_bdd/parser.py | 8 +++++++- pytest_bdd/scenario.py | 30 ++++++++++++++++++++---------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/pytest_bdd/parser.py b/pytest_bdd/parser.py index 8cbfbb1..81a133e 100644 --- a/pytest_bdd/parser.py +++ b/pytest_bdd/parser.py @@ -228,10 +228,15 @@ class ScenarioTemplate: self.feature = feature self.name = name self._steps: typing.List[Step] = [] - self.examples = Examples() + self.example_tables = [Examples()] self.line_number = line_number self.tags = tags or set() + @property + def examples(self): + """Current examples.""" + return self.example_tables[-1] + def add_step(self, step): """Add step to the scenario. @@ -246,6 +251,7 @@ class ScenarioTemplate: return (background.steps if background else []) + self._steps def render(self, context: typing.Mapping[str, typing.Any]) -> "Scenario": + """Render a single scenario given a context (examples).""" steps = [ Step( name=templated_step.render(context), diff --git a/pytest_bdd/scenario.py b/pytest_bdd/scenario.py index c9446e3..9686189 100644 --- a/pytest_bdd/scenario.py +++ b/pytest_bdd/scenario.py @@ -200,19 +200,29 @@ def collect_example_parametrizations( # We need to evaluate these iterators and store them as lists, otherwise # we won't be able to do the cartesian product later (the second iterator will be consumed) feature_contexts = list(templated_scenario.feature.examples.as_contexts()) - scenario_contexts = list(templated_scenario.examples.as_contexts()) - - contexts = [ - {**feature_context, **scenario_context} + parametrizations = [] + has_multiple_examples = len(templated_scenario.example_tables) > 1 + for example_id, examples in enumerate(templated_scenario.example_tables): + scenario_contexts = list(examples.as_contexts()) # We must make sure that we always have at least one element in each list, otherwise # the cartesian product will result in an empty list too, even if one of the 2 sets # is non empty. - for feature_context in feature_contexts or [{}] - for scenario_context in scenario_contexts or [{}] - ] - if contexts == [{}]: - return None - return [pytest.param(context, id="-".join(context.values())) for context in contexts] + for feature_context in feature_contexts or [{}]: + for scenario_context in scenario_contexts or [{}]: + context = {**feature_context, **scenario_context} + if context: + test_id = "-".join(context.values()) + if has_multiple_examples: + test_id = "-".join((str(example_id), test_id)) + parametrizations.append( + pytest.param( + context, + id=test_id, + # marks=... # TODO: Example Tags + ), + ) + + return parametrizations or None def scenario(feature_name: str, scenario_name: str, encoding: str = "utf-8", features_base_dir=None):