From e19552afbe49b8a16c71a190d1c80cd748411522 Mon Sep 17 00:00:00 2001 From: Guido Schmitz Date: Tue, 13 Feb 2024 21:22:56 +0100 Subject: [PATCH 1/2] Make pytest-adaptavist compatible with pytest 8 --- CHANGELOG.md | 12 +++++++++ pytest_adaptavist/__init__.py | 16 ++---------- pytest_adaptavist/_pytest_adaptavist.py | 33 +++--------------------- pytest_adaptavist/metablock.py | 8 +++--- setup.py | 2 +- tests/test_pytest_adaptavist.py | 34 +++++-------------------- 6 files changed, 29 insertions(+), 76 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8c18d4..8927be2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Breaking change + +* Parameters test_run_name and test_plan_name deprecated in 5.6.0 are removed now. Please use test-cycle-name and test-plan-name instead. +* [Following pytest 7](https://docs.pytest.org/en/stable/deprecations.html#passing-msg-to-pytest-skip-pytest-fail-or-pytest-exit), pytest.block needs the keyword argument reason now instead of msg. + +### Changed + +* pytest 7 is now needed as minimum. +* pytest 8 is supported. + ## [5.8.0] - 2022/10/13 ### Added diff --git a/pytest_adaptavist/__init__.py b/pytest_adaptavist/__init__.py index 63447d6..3e08833 100644 --- a/pytest_adaptavist/__init__.py +++ b/pytest_adaptavist/__init__.py @@ -66,18 +66,6 @@ def add_option_ini( default="origin/master", help="Branch to restrict to (default: origin/master).", ) - add_option_ini( - "--test_run_name", - dest="test_run_name", - default=TEST_CYCLE_NAME_DEFAULT, - help="Specify test run name (default: ).", - ) # deprecated - add_option_ini( - "--test_plan_name", - dest="test_plan_name_deprecated", - default=TEST_PLAN_NAME_DEFAULT, - help="Specify test plan name (default: ).", - ) # deprecated add_option_ini( "--test-cycle-name", dest="test_cycle_name", @@ -138,9 +126,9 @@ def pytest_configure(config: Config): # Support for pytest.block @_with_exception(Blocked) - def block(msg="") -> NoReturn: + def block(reason="") -> NoReturn: __tracebackhide__ = True # pylint: disable=unused-variable - raise Blocked(msg=msg) + raise Blocked(msg=reason) pytest.block = block # type: ignore diff --git a/pytest_adaptavist/_pytest_adaptavist.py b/pytest_adaptavist/_pytest_adaptavist.py index e6e92b7..dcfa9b8 100644 --- a/pytest_adaptavist/_pytest_adaptavist.py +++ b/pytest_adaptavist/_pytest_adaptavist.py @@ -15,7 +15,6 @@ import pytest from _pytest._io.saferepr import saferepr from _pytest.config import Config -from _pytest.deprecated import PytestDeprecationWarning from _pytest.mark.structures import Mark from _pytest.outcomes import fail from _pytest.reports import TestReport @@ -35,7 +34,6 @@ html_row, intersection, ) -from .constants import TEST_CYCLE_NAME_DEFAULT, TEST_PLAN_NAME_DEFAULT class PytestAdaptavist: @@ -50,17 +48,6 @@ class PytestAdaptavist: def __init__(self, config: Config): self.config = config - if get_option_ini(config, "test_run_name") != TEST_CYCLE_NAME_DEFAULT: # TODO: Remove in pytest-adaptavist 6 - config.issue_config_time_warning( - PytestDeprecationWarning("test_run_name is deprecated. Please use --test-cycle-name"), stacklevel=2 - ) - if ( - get_option_ini(config, "test_plan_name_deprecated") != TEST_PLAN_NAME_DEFAULT - ): # TODO: Remove in pytest-adaptavist 6 - config.issue_config_time_warning( - PytestDeprecationWarning("test_plan_name is deprecated. Please use --test-plan-name"), stacklevel=2 - ) - self.item_status_info: dict[str, Any] = {} self.test_refresh_info: dict[str, Any] = {} self.test_result_data: dict[str, Any] = {} @@ -173,7 +160,7 @@ def pytest_runtest_setup(self, item: pytest.Item): if not skip_status.kwargs.get("reason", ""): fail("You need to specify a reason when blocking conditionally.", pytrace=False) elif any(skip_status.args): - pytest.block(msg=skip_status.kwargs["reason"]) # type: ignore + pytest.block(reason=skip_status.kwargs["reason"]) # type: ignore if skip_status := item.get_closest_marker("block"): fullname = get_item_nodeid(item) @@ -183,7 +170,7 @@ def pytest_runtest_setup(self, item: pytest.Item): ): skip_reason = self.test_result_data[fullname].get("comment", "") if skip_status.name == "block": - pytest.block(msg=skip_reason) # type: ignore + pytest.block(reason=skip_reason) # type: ignore @pytest.hookimpl() def pytest_runtest_logreport(self, report: TestReport): @@ -612,20 +599,8 @@ def _setup_report(self, worker_input: dict[str, Any]): * New test plans are named like " " (where test plan suffix must be unique) * New test runs are named like " " """ - test_run_name = self._eval_format( - str( - self.config.getini("test_cycle_name") - if self.config.getini("test_cycle_name") != TEST_CYCLE_NAME_DEFAULT - else self.config.getini("test_run_name") - ) - ) # TODO: Remove 'if' in pytest-adaptavist 6. Hint for future-me ;) self._eval_format(str(self.config.getini("test_cycle_name"))) - test_plan_name = self._eval_format( - str( - self.config.getini("test_plan_name") - if self.config.getini("test_plan_name") != TEST_PLAN_NAME_DEFAULT - else self.config.getini("test_plan_name_deprecated") - ) - ) # TODO: Remove 'if' in pytest-adaptavist 6 + test_run_name = self._eval_format(str(self.config.getini("test_cycle_name"))) + test_plan_name = self._eval_format(str(self.config.getini("test_plan_name"))) if self.project_key: if not self.test_plan_key and self.test_plan_suffix: diff --git a/pytest_adaptavist/metablock.py b/pytest_adaptavist/metablock.py index a043452..bacdb1d 100644 --- a/pytest_adaptavist/metablock.py +++ b/pytest_adaptavist/metablock.py @@ -264,14 +264,14 @@ def _process_failed_condition(self, action_on_fail: Action, message_on_fail: str elif action_on_fail == self.Action.STOP_METHOD: # STOP_METHOD: skip execution of this block/test, set it to 'Blocked' and continue with next test self.data["blocked"] = True - pytest.skip(msg=f"Blocked. {self.item_name} failed: {message_on_fail}") + pytest.skip(reason=f"Blocked. {self.item_name} failed: {message_on_fail}") elif action_on_fail == self.Action.STOP_SESSION: # STOP_SESSION: skip execution of this block/test, set it to 'Blocked' and block following tests as well for item in self.items: item.add_marker("block") self.adaptavist.test_result_data[fullname]["blocked"] = True self.adaptavist.test_result_data[fullname]["comment"] = f"Blocked. {self.item_name} failed: {message_on_fail}" - pytest.block(msg=message_on_fail) # type:ignore + pytest.block(reason=message_on_fail) # type:ignore elif action_on_fail == self.Action.FAIL_SESSION: # FAIL_SESSION: skip execution of this block/test, set it to 'Fail' and block following tests for item in self.items: @@ -285,10 +285,10 @@ def _process_failed_condition(self, action_on_fail: Action, message_on_fail: str elif action_on_fail == self.Action.STOP_EXIT_SESSION: # EXIT_SESSION: skip execution of this block/test, set it to 'Blocked' and exit session self.item.add_marker("block") - pytest.exit(msg=f"Exiting pytest. {self.item_name} failed: {message_on_fail}", returncode=1) + pytest.exit(reason=f"Exiting pytest. {self.item_name} failed: {message_on_fail}", returncode=1) elif action_on_fail == self.Action.FAIL_EXIT_SESSION: # EXIT_SESSION: skip execution of this block/test, set it to 'Blocked' and exit session - pytest.exit(msg=f"Exiting pytest. {self.item_name} failed: {message_on_fail}") + pytest.exit(reason=f"Exiting pytest. {self.item_name} failed: {message_on_fail}") else: # CONTINUE: try to collect failed assumption, set result to 'Fail' and continue pytest.assume(expr=False, msg=message_on_fail) # type:ignore diff --git a/setup.py b/setup.py index 24cedd3..ab1dcdf 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ entry_points={"pytest11": ["adaptavist = pytest_adaptavist"]}, platforms="any", python_requires=">=3.8", - install_requires=["adaptavist>=2.1.0", "pytest>=5.4.0", "pytest-assume>=2.3.2", "pytest-metadata>=1.6.0"], + install_requires=["adaptavist>=2.1.0", "pytest>=7.0.0", "pytest-assume>=2.3.2", "pytest-metadata>=1.6.0"], extras_require={"test": ["beautifulsoup4", "lxml", "requests"]}, setup_requires=["setuptools_scm"], keywords="python pytest adaptavist kanoah tm4j jira test testmanagement report", diff --git a/tests/test_pytest_adaptavist.py b/tests/test_pytest_adaptavist.py index 84d24a6..1d01e6c 100644 --- a/tests/test_pytest_adaptavist.py +++ b/tests/test_pytest_adaptavist.py @@ -45,7 +45,7 @@ def test_T123(meta_block): """ ) with open("config/global_config.json", "w", encoding="utf8") as file: - file.write('{"test_run_key":"TEST-C1"}') + file.write('{"test_cycle_key":"TEST-C1"}') hook_record = pytester.inline_run("--adaptavist") assert hook_record.matchreport().head_line == "test_T123" @@ -177,17 +177,17 @@ def test_T124(meta_block): ) # Test that test cases skipped if append-to-cycle is off and test_case_keys are set with open("config/global_config.json", "w", encoding="utf8") as file: - file.write('{"project_key": "TEST", "test_run_key":"TEST-C1", "test_case_keys": ["TEST-T123"]}') + file.write('{"project_key": "TEST", "test_cycle_key":"TEST-C1", "test_case_keys": ["TEST-T123"]}') pytester.runpytest("--adaptavist").assert_outcomes(passed=1, skipped=2) # Test that test cases which are not defined in test_case_keys are skipped if append-to-cycle is on with open("config/global_config.json", "w", encoding="utf8") as file: - file.write('{"project_key": "TEST", "test_run_key":"TEST-C1", "test_case_keys": ["TEST-T125"]}') + file.write('{"project_key": "TEST", "test_cycle_key":"TEST-C1", "test_case_keys": ["TEST-T125"]}') pytester.runpytest("--adaptavist", "--append-to-cycle").assert_outcomes(failed=1, skipped=2) # Test that test cases run if append-to-cycle is on and test_case_keys are not set with open("config/global_config.json", "w", encoding="utf8") as file: - file.write('{"project_key": "TEST", "test_run_key":"TEST-C1", "test_case_keys": []}') + file.write('{"project_key": "TEST", "test_cycle_key":"TEST-C1", "test_case_keys": []}') pytester.runpytest("--adaptavist", "--append-to-cycle").assert_outcomes(passed=2, failed=1) @pytest.mark.usefixtures("adaptavist_mock") @@ -249,28 +249,6 @@ def test_T123(self, meta_block): assert etrs.call_args_list[0].kwargs["test_case_key"] == "TEST-T123" assert etrs.call_count == 1 - @pytest.mark.filterwarnings("default") - @pytest.mark.usefixtures("adaptavist_mock") - def test_deprecated_options(self, pytester: pytest.Pytester): - """Test deprecated options.""" - pytester.makepyfile( - """ - def test_dummy(): - assert True - """ - ) - result = pytester.runpytest("--test_run_name=abc", "--adaptavist") - assert any( - "PytestDeprecationWarning: test_run_name is deprecated. Please use --test-cycle-name" in line - for line in result.outlines - ) - - result = pytester.runpytest("--test_plan_name=abc", "--adaptavist") - assert any( - "PytestDeprecationWarning: test_plan_name is deprecated. Please use --test-plan-name" in line - for line in result.outlines - ) - @pytest.mark.usefixtures("adaptavist_mock") def test_test_run_name(self, pytester: pytest.Pytester): """Test that test_run_name template is working.""" @@ -298,7 +276,7 @@ def test_T123(self, meta_block): pytester.makeini( """ [pytest] - test_run_name = Change test_run_name %(project_key) + test_cycle_name = Change test_run_name %(project_key) """ ) pytester.runpytest("--adaptavist") @@ -360,7 +338,7 @@ def test_T123(self, meta_block): pytester.makeini( """ [pytest] - test_run_name = Change test_run_name %(project_ey) + test_cycle_name = Change test_run_name %(project_ey) """ ) outcome = pytester.runpytest("--adaptavist") From 1b225cfe294a2e32d1679502e578bcc49d3790c2 Mon Sep 17 00:00:00 2001 From: Guido Schmitz Date: Tue, 13 Feb 2024 21:39:49 +0100 Subject: [PATCH 2/2] Fix tests --- tests/test_pytest_adaptavist.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_pytest_adaptavist.py b/tests/test_pytest_adaptavist.py index 1d01e6c..ec0ba9f 100644 --- a/tests/test_pytest_adaptavist.py +++ b/tests/test_pytest_adaptavist.py @@ -222,11 +222,11 @@ def test_b(meta_block): ) outcome = pytester.runpytest() regex = re.findall("\\(not True", str(outcome.outlines).replace("'", "").replace("[", "").replace("]", "")) - assert len(regex) == 2 if running_on_ci() else 1 + assert len(regex) == 3 if running_on_ci() else 1 regex = re.findall("\\(False", str(outcome.outlines).replace("'", "").replace("[", "").replace("]", "")) - assert len(regex) == 2 if running_on_ci() else 1 + assert len(regex) == 3 if running_on_ci() else 1 regex = re.findall("\\(not not False", str(outcome.outlines).replace("'", "").replace("[", "").replace("]", "")) - assert len(regex) == 2 if running_on_ci() else 1 + assert len(regex) == 3 if running_on_ci() else 1 def test_reporting_skipped_test_cases(self, pytester: pytest.Pytester, adaptavist_mock: AdaptavistMock): """Don't report a test case if it is not in test_case_keys."""