diff --git a/pytest_bdd/cucumber_json.py b/pytest_bdd/cucumber_json.py index 71b9feab0..41b8dc4c0 100644 --- a/pytest_bdd/cucumber_json.py +++ b/pytest_bdd/cucumber_json.py @@ -32,7 +32,7 @@ def add_options(parser): "--cucumberjson-expanded", "--cucumber-json-expanded", action="store_true", - dest="expand", + dest="cucumber_json_expanded", default=False, help="expand scenario outlines into scenarios and fill in the step names", ) @@ -42,7 +42,7 @@ def configure(config): cucumber_json_path = config.option.cucumber_json_path # prevent opening json log on slave nodes (xdist) if cucumber_json_path and not hasattr(config, "slaveinput"): - config._bddcucumberjson = LogBDDCucumberJSON(cucumber_json_path, expand=config.option.expand) + config._bddcucumberjson = LogBDDCucumberJSON(cucumber_json_path, expand=config.option.cucumber_json_expanded) config.pluginmanager.register(config._bddcucumberjson) diff --git a/pytest_bdd/gherkin_terminal_reporter.py b/pytest_bdd/gherkin_terminal_reporter.py index f846084a9..0d727895c 100644 --- a/pytest_bdd/gherkin_terminal_reporter.py +++ b/pytest_bdd/gherkin_terminal_reporter.py @@ -21,14 +21,14 @@ def add_options(parser): group._addoption( "--gherkin-terminal-reporter-expanded", action="store_true", - dest="expand", + dest="gherkin_expanded", default=False, - help="expand scenario outlines into scenarios and fill in the step names", + help="enable gherkin output, expand scenario outlines into scenarios and fill in the step names", ) def configure(config): - if config.option.gherkin_terminal_reporter: + if config.option.gherkin_terminal_reporter or config.option.gherkin_expanded: # Get the standard terminal reporter plugin and replace it with our current_reporter = config.pluginmanager.getplugin('terminalreporter') if current_reporter.__class__ != TerminalReporter: @@ -100,12 +100,12 @@ def pytest_runtest_logreport(self, report): self._tw.write(report.scenario['name'], **scenario_markup) self._tw.write('\n') for step in report.scenario['steps']: - if self.config.option.expand: + if self.config.option.gherkin_expanded: step_name = self._format_step_name(step['name'], **report.scenario['example_kwargs']) else: step_name = step['name'] - self._tw.write(' {} {}\n'.format(step['keyword'], - step_name), **scenario_markup) + self._tw.write(u' {} {}\n'.format(step['keyword'], + step_name), **scenario_markup) self._tw.write(' ' + word, **word_markup) self._tw.write('\n\n') else: diff --git a/pytest_bdd/reporting.py b/pytest_bdd/reporting.py index f99d54c79..723105562 100644 --- a/pytest_bdd/reporting.py +++ b/pytest_bdd/reporting.py @@ -7,7 +7,7 @@ import time from .feature import force_unicode -from .utils import get_parametrize_markers_args +from .utils import get_parametrize_markers_args, get_parametrize_params class StepReport(object): @@ -73,20 +73,30 @@ def __init__(self, scenario, node): """ self.scenario = scenario self.step_reports = [] - self.param_index = None + parametrize_args = get_parametrize_markers_args(node) - if parametrize_args and scenario.examples: - param_names = parametrize_args[0] if isinstance(parametrize_args[0], (tuple, list)) else [ - parametrize_args[0]] - param_values = parametrize_args[1] + params = get_parametrize_params(parametrize_args) + + self.param_index = self.get_param_index(node, params) + self.example_kwargs = self.get_example_kwargs(node, params) + + def get_param_index(self, node, params): + if params: + param_names = params[0]['names'] + param_values = params[0]['values'] node_param_values = [node.funcargs[param_name] for param_name in param_names] if node_param_values in param_values: - self.param_index = param_values.index(node_param_values) + return param_values.index(node_param_values) elif tuple(node_param_values) in param_values: - self.param_index = param_values.index(tuple(node_param_values)) - self.example_kwargs = { - example_param: force_unicode(node.funcargs[example_param]) - for example_param in scenario.get_example_params() + return param_values.index(tuple(node_param_values)) + return None + + def get_example_kwargs(self, node, params): + params_names = (param['names'] for param in params) + all_names = sum(params_names, []) + return { + example_param_name: force_unicode(node.funcargs[example_param_name]) + for example_param_name in all_names } @property diff --git a/pytest_bdd/utils.py b/pytest_bdd/utils.py index 7fdfa7f23..c2121cc4d 100644 --- a/pytest_bdd/utils.py +++ b/pytest_bdd/utils.py @@ -110,3 +110,33 @@ def get_markers_args_using_iter_markers(node, mark_name): def get_markers_args_using_get_marker(node, mark_name): """Deprecated on pytest>=3.6""" return getattr(node.get_marker(mark_name), 'args', ()) + + +def get_parametrize_params(parametrize_args): + """Group parametrize markers arguments names and values. + + :param parametrize_args: parametrize markers arguments. + :return: `list` of `dict` in the form of: + [ + { + "names": ["name1", "name2", ...], + "values": [value1, value2, ...], + }, + ... + ] + """ + params = [] + for i in range(0, len(parametrize_args), 2): + params.append({ + 'names': _get_param_names(parametrize_args[i]), + 'values': parametrize_args[i+1] + }) + return params + + +def _get_param_names(names): + if not isinstance(names, (tuple, list)): + # As pytest.mark.parametrize has only one param name, + # it is not returned as a list. Convert it to list: + names = [names] + return names diff --git a/tests/feature/gherkin_terminal_reporter.feature b/tests/feature/gherkin_terminal_reporter.feature index 4f8d09396..95f2ceb7f 100644 --- a/tests/feature/gherkin_terminal_reporter.feature +++ b/tests/feature/gherkin_terminal_reporter.feature @@ -43,5 +43,10 @@ Feature: Gherkin terminal reporter Scenario: Should step parameters be replaced by their values Given there is gherkin scenario outline implemented - When tests are run with step expanded mode + When tests are run with step expanded option + Then output must contain parameters values + + Scenario: Should step parameters be replaced by their values also when used together with gherkin reporter option + Given there is gherkin scenario outline implemented + When tests are run with step expanded and gherkin reporter options Then output must contain parameters values diff --git a/tests/feature/outline_feature.feature b/tests/feature/outline_feature.feature index 98280b1d5..992fc81fa 100644 --- a/tests/feature/outline_feature.feature +++ b/tests/feature/outline_feature.feature @@ -4,6 +4,7 @@ Feature: Outline | start | eat | left | | 12 | 5 | 7 | | 5 | 4 | 1 | + | 4 | 2 | 2 | Scenario Outline: Outlined given, when, thens Given there are diff --git a/tests/feature/parametrized.feature b/tests/feature/parametrized.feature index 70953cc89..7febc15b9 100644 --- a/tests/feature/parametrized.feature +++ b/tests/feature/parametrized.feature @@ -2,3 +2,7 @@ Scenario: Parametrized given, when, thens Given there are cucumbers When I eat cucumbers Then I should have cucumbers + + +Scenario: Parametrized given - single param + Given there are cucumbers diff --git a/tests/feature/test_gherkin_terminal_reporter.py b/tests/feature/test_gherkin_terminal_reporter.py index 1fab65982..f2d989ce6 100644 --- a/tests/feature/test_gherkin_terminal_reporter.py +++ b/tests/feature/test_gherkin_terminal_reporter.py @@ -60,6 +60,12 @@ def test_Should_step_parameters_be_replaced_by_their_values(): pass +@scenario('gherkin_terminal_reporter.feature', + 'Should step parameters be replaced by their values also when used together with gherkin reporter option') +def test_Should_step_parameters_be_replaced_by_their_values_also_when_used_together_with_gherkin_reporter_option(): + pass + + @pytest.fixture(params=[0, 1, 2], ids=['compact mode', 'line per test', 'verbose']) def verbosity_mode(request): @@ -184,8 +190,17 @@ def tests_are_run_with_very_verbose_mode(testdir, test_execution): test_execution['gherkin'] = testdir.runpytest('--gherkin-terminal-reporter', '-vv') -@when("tests are run with step expanded mode") -def tests_are_run_with_step_expanded_mode(testdir, test_execution): +@when("tests are run with step expanded option") +def tests_are_run_with_step_expanded_option(testdir, test_execution): + test_execution['regular'] = testdir.runpytest('-vv') + test_execution['gherkin'] = testdir.runpytest( + '--gherkin-terminal-reporter-expanded', + '-vv', + ) + + +@when("tests are run with step expanded and gherkin reporter options") +def tests_are_run_with_step_expanded_and_gherkin_reporter_options(testdir, test_execution): test_execution['regular'] = testdir.runpytest('-vv') test_execution['gherkin'] = testdir.runpytest( '--gherkin-terminal-reporter', diff --git a/tests/feature/test_outline.py b/tests/feature/test_outline.py index afddaa815..ca6bcb155 100644 --- a/tests/feature/test_outline.py +++ b/tests/feature/test_outline.py @@ -168,7 +168,7 @@ def should_have_left_fruits(start_fruits, start, eat, left, fruits): def test_outlined_feature(request): assert get_parametrize_markers_args(request.node) == ( ['start', 'eat', 'left'], - [[12, 5.0, '7'], [5, 4.0, '1']], + [[12, 5.0, '7'], [5, 4.0, '1'], [4, 2.0, '2']], ['fruits'], [[u'oranges'], [u'apples']] ) diff --git a/tests/feature/test_parametrized.py b/tests/feature/test_parametrized.py index 7dfd76da9..bb8396b48 100644 --- a/tests/feature/test_parametrized.py +++ b/tests/feature/test_parametrized.py @@ -14,6 +14,17 @@ def test_parametrized(request, start, eat, left): """Test parametrized scenario.""" +@pytest.mark.parametrize( + 'start', [12] +) +@scenario( + 'parametrized.feature', + 'Parametrized given - single param', +) +def test_parametrized_single_param(request, start): + """Test parametrized scenario.""" + + @pytest.fixture(params=[1, 2]) def foo_bar(request): return 'bar' * request.param