From 6da2cab12d9386899fc07701e87053488f1ed166 Mon Sep 17 00:00:00 2001 From: Sergey Khomutinin <31664571+skhomuti@users.noreply.github.com> Date: Mon, 7 Nov 2022 18:07:20 +0400 Subject: [PATCH] add dynamic.parameter function (fixes #699, via #565) --- allure-pytest/src/listener.py | 16 +++- .../parametrization/parametrization_test.py | 83 ++++++++++++++++++- allure-python-commons-test/src/result.py | 13 ++- allure-python-commons/allure.py | 4 +- allure-python-commons/src/_allure.py | 6 +- allure-python-commons/src/_hooks.py | 4 + allure-python-commons/src/model2.py | 2 + allure-python-commons/src/types.py | 6 ++ 8 files changed, 127 insertions(+), 7 deletions(-) diff --git a/allure-pytest/src/listener.py b/allure-pytest/src/listener.py index d56751b5..16327824 100644 --- a/allure-pytest/src/listener.py +++ b/allure-pytest/src/listener.py @@ -13,7 +13,7 @@ from allure_commons.model2 import Parameter from allure_commons.model2 import Label, Link from allure_commons.model2 import Status -from allure_commons.types import LabelType, AttachmentType +from allure_commons.types import LabelType, AttachmentType, ParameterMode from allure_pytest.utils import allure_description, allure_description_html from allure_pytest.utils import allure_labels, allure_links, pytest_markers from allure_pytest.utils import allure_full_name, allure_package, allure_name @@ -96,8 +96,10 @@ def pytest_runtest_setup(self, item): test_result.testCaseId = md5(full_name) test_result.description = allure_description(item) test_result.descriptionHtml = allure_description_html(item) + current_param_names = [param.name for param in test_result.parameters] test_result.parameters.extend( - [Parameter(name=name, value=represent(value)) for name, value in params.items()]) + [Parameter(name=name, value=represent(value)) for name, value in params.items() + if name not in current_param_names]) @pytest.hookimpl(hookwrapper=True) def pytest_runtest_call(self, item): @@ -266,6 +268,16 @@ def add_label(self, label_type, labels): for label in labels if test_result else (): test_result.labels.append(Label(label_type, label)) + @allure_commons.hookimpl + def add_parameter(self, name, value, excluded, mode: ParameterMode): + test_result: TestResult = self.allure_logger.get_test(None) + existing_param = next(filter(lambda x: x.name == name, test_result.parameters), None) + if existing_param: + existing_param.value = represent(value) + else: + test_result.parameters.append(Parameter(name=name, value=represent(value), + excluded=excluded or None, mode=mode.value if mode else None)) + class ItemCache(object): diff --git a/allure-pytest/test/acceptance/parametrization/parametrization_test.py b/allure-pytest/test/acceptance/parametrization/parametrization_test.py index 77b15e24..03242f85 100644 --- a/allure-pytest/test/acceptance/parametrization/parametrization_test.py +++ b/allure-pytest/test/acceptance/parametrization/parametrization_test.py @@ -1,7 +1,7 @@ import pytest from hamcrest import assert_that from allure_commons_test.report import has_test_case -from allure_commons_test.result import has_parameter +from allure_commons_test.result import has_parameter, with_excluded, with_mode def params_name(request): @@ -92,3 +92,84 @@ def test_parametrization_many_decorators_with_partial_ids(executed_docstring_sou ) ) + + +def test_dynamic_parameter_add(executed_docstring_source): + """ + >>> import allure + + >>> def test_parameter_add(): + ... allure.dynamic.parameter("param1", "param-value") + """ + assert_that(executed_docstring_source.allure_report, + has_test_case("test_parameter_add", + has_parameter("param1", "'param-value'") + ) + ) + + +def test_dynamic_parameter_excluded(executed_docstring_source): + """ + >>> import allure + + >>> def test_parameter_excluded(): + ... allure.dynamic.parameter("param1", "param-value", excluded=True) + """ + assert_that(executed_docstring_source.allure_report, + has_test_case("test_parameter_excluded", + has_parameter("param1", "'param-value'", + with_excluded()) + ) + ) + + +def test_dynamic_parameter_mode(executed_docstring_source): + """ + >>> import allure + + >>> def test_parameter_mode(): + ... allure.dynamic.parameter("param1", "param-value", mode=allure.parameter_mode.MASKED) + """ + assert_that(executed_docstring_source.allure_report, + has_test_case("test_parameter_mode", + has_parameter("param1", "'param-value'", + with_mode('masked')) + ) + ) + + +def test_dynamic_parameter_override(executed_docstring_source): + """ + >>> import pytest + ... import allure + + >>> @pytest.mark.parametrize("param1", [object()], ids=["param-id"]) + ... def test_parameter_override(param1): + ... allure.dynamic.parameter("param1", "readable-value") + """ + assert_that(executed_docstring_source.allure_report, + has_test_case("test_parameter_override[param-id]", + has_parameter("param1", "'readable-value'") + ) + ) + + +def test_dynamic_parameter_override_from_fixture(executed_docstring_source): + """ + >>> import pytest + ... import allure + + + >>> @pytest.fixture() + ... def fixt(): + ... allure.dynamic.parameter("param1", "readable-value") + + >>> @pytest.mark.parametrize("param1", [object()], ids=["param-id"]) + ... def test_parameter_override_from_fixture(fixt, param1): + ... pass + """ + assert_that(executed_docstring_source.allure_report, + has_test_case("test_parameter_override_from_fixture[param-id]", + has_parameter("param1", "'readable-value'") + ) + ) diff --git a/allure-python-commons-test/src/result.py b/allure-python-commons-test/src/result.py index acecd9bf..ad38e34f 100644 --- a/allure-python-commons-test/src/result.py +++ b/allure-python-commons-test/src/result.py @@ -90,12 +90,13 @@ def has_step(name, *matchers): )) -def has_parameter(name, value): +def has_parameter(name, value, *matchers): return has_entry('parameters', has_item( all_of( has_entry('name', equal_to(name)), - has_entry('value', equal_to(value)) + has_entry('value', equal_to(value)), + *matchers ) )) @@ -158,5 +159,13 @@ def with_trace_contains(string): return has_entry('trace', contains_string(string)) +def with_excluded(): + return has_entry('excluded', True) + + +def with_mode(mode): + return has_entry('mode', mode) + + def has_history_id(): return has_entry('historyId', anything()) diff --git a/allure-python-commons/allure.py b/allure-python-commons/allure.py index 58f2891f..4acb83e3 100644 --- a/allure-python-commons/allure.py +++ b/allure-python-commons/allure.py @@ -13,6 +13,7 @@ from allure_commons._allure import manual from allure_commons.types import Severity as severity_level from allure_commons.types import AttachmentType as attachment_type +from allure_commons.types import ParameterMode as parameter_mode __all__ = [ @@ -32,10 +33,11 @@ 'link', 'issue', 'testcase', + 'manual', 'step', 'dynamic', 'severity_level', 'attach', 'attachment_type', - 'manual' + 'parameter_mode' ] diff --git a/allure-python-commons/src/_allure.py b/allure-python-commons/src/_allure.py index 68580502..262b5944 100644 --- a/allure-python-commons/src/_allure.py +++ b/allure-python-commons/src/_allure.py @@ -2,7 +2,7 @@ from typing import Any, Callable, TypeVar from allure_commons._core import plugin_manager -from allure_commons.types import LabelType, LinkType +from allure_commons.types import LabelType, LinkType, ParameterMode from allure_commons.utils import uuid4 from allure_commons.utils import func_parameters, represent @@ -132,6 +132,10 @@ def id(id): def link(url, link_type=LinkType.LINK, name=None): plugin_manager.hook.add_link(url=url, link_type=link_type, name=name) + @staticmethod + def parameter(name, value, excluded=None, mode: ParameterMode = None): + plugin_manager.hook.add_parameter(name=name, value=value, excluded=excluded, mode=mode) + @staticmethod def issue(url, name=None): Dynamic.link(url, link_type=LinkType.ISSUE, name=name) diff --git a/allure-python-commons/src/_hooks.py b/allure-python-commons/src/_hooks.py index 724c3e01..8695c24c 100644 --- a/allure-python-commons/src/_hooks.py +++ b/allure-python-commons/src/_hooks.py @@ -46,6 +46,10 @@ def decorate_as_link(self, url, link_type, name): def add_link(self, url, link_type, name): """ url """ + @hookspec + def add_parameter(self, name, value, excluded, mode): + """ parameter """ + @hookspec def start_step(self, uuid, title, params): """ step """ diff --git a/allure-python-commons/src/model2.py b/allure-python-commons/src/model2.py index 074bff94..62f59cab 100644 --- a/allure-python-commons/src/model2.py +++ b/allure-python-commons/src/model2.py @@ -70,6 +70,8 @@ class TestAfterResult(ExecutableItem): class Parameter(object): name = attrib(default=None) value = attrib(default=None) + excluded = attrib(default=None) + mode = attrib(default=None) @attrs diff --git a/allure-python-commons/src/types.py b/allure-python-commons/src/types.py index 321a7f0c..56030766 100644 --- a/allure-python-commons/src/types.py +++ b/allure-python-commons/src/types.py @@ -63,3 +63,9 @@ def __init__(self, mime_type, extension): WEBM = ("video/webm", "webm") PDF = ("application/pdf", "pdf") + + +class ParameterMode(Enum): + HIDDEN = 'hidden' + MASKED = 'masked' + DEFAULT = None