diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 6c1d9c69a..74168efd5 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -256,6 +256,7 @@ default_plugins = essential_plugins + ( builtin_plugins = set(default_plugins) builtin_plugins.add("pytester") +builtin_plugins.add("pytester_assertions") def get_config( diff --git a/src/_pytest/pytester.py b/src/_pytest/pytester.py index 0e1dffb9d..158b71b3a 100644 --- a/src/_pytest/pytester.py +++ b/src/_pytest/pytester.py @@ -1,4 +1,7 @@ -"""(Disabled by default) support for testing pytest and pytest plugins.""" +"""(Disabled by default) support for testing pytest and pytest plugins. + +PYTEST_DONT_REWRITE +""" import collections.abc import contextlib import gc @@ -66,6 +69,9 @@ if TYPE_CHECKING: import pexpect +pytest_plugins = ["pytester_assertions"] + + IGNORE_PAM = [ # filenames added when obtaining details about the current user "/var/lib/sss/mc/passwd" ] @@ -408,16 +414,12 @@ class HookRecorder: def assertoutcome(self, passed: int = 0, skipped: int = 0, failed: int = 0) -> None: __tracebackhide__ = True + from _pytest.pytester_assertions import assertoutcome outcomes = self.listoutcomes() - realpassed, realskipped, realfailed = outcomes - obtained = { - "passed": len(realpassed), - "skipped": len(realskipped), - "failed": len(realfailed), - } - expected = {"passed": passed, "skipped": skipped, "failed": failed} - assert obtained == expected, outcomes + assertoutcome( + outcomes, passed=passed, skipped=skipped, failed=failed, + ) def clear(self) -> None: self.calls[:] = [] @@ -574,25 +576,18 @@ class RunResult: """Assert that the specified outcomes appear with the respective numbers (0 means it didn't occur) in the text output from a test run.""" __tracebackhide__ = True + from _pytest.pytester_assertions import assert_outcomes - d = self.parseoutcomes() - obtained = { - "passed": d.get("passed", 0), - "skipped": d.get("skipped", 0), - "failed": d.get("failed", 0), - "errors": d.get("errors", 0), - "xpassed": d.get("xpassed", 0), - "xfailed": d.get("xfailed", 0), - } - expected = { - "passed": passed, - "skipped": skipped, - "failed": failed, - "errors": errors, - "xpassed": xpassed, - "xfailed": xfailed, - } - assert obtained == expected + outcomes = self.parseoutcomes() + assert_outcomes( + outcomes, + passed=passed, + skipped=skipped, + failed=failed, + errors=errors, + xpassed=xpassed, + xfailed=xfailed, + ) class CwdSnapshot: diff --git a/src/_pytest/pytester_assertions.py b/src/_pytest/pytester_assertions.py new file mode 100644 index 000000000..630c1d333 --- /dev/null +++ b/src/_pytest/pytester_assertions.py @@ -0,0 +1,66 @@ +"""Helper plugin for pytester; should not be loaded on its own.""" +# This plugin contains assertions used by pytester. pytester cannot +# contain them itself, since it is imported by the `pytest` module, +# hence cannot be subject to assertion rewriting, which requires a +# module to not be already imported. +from typing import Dict +from typing import Sequence +from typing import Tuple +from typing import Union + +from _pytest.reports import CollectReport +from _pytest.reports import TestReport + + +def assertoutcome( + outcomes: Tuple[ + Sequence[TestReport], + Sequence[Union[CollectReport, TestReport]], + Sequence[Union[CollectReport, TestReport]], + ], + passed: int = 0, + skipped: int = 0, + failed: int = 0, +) -> None: + __tracebackhide__ = True + + realpassed, realskipped, realfailed = outcomes + obtained = { + "passed": len(realpassed), + "skipped": len(realskipped), + "failed": len(realfailed), + } + expected = {"passed": passed, "skipped": skipped, "failed": failed} + assert obtained == expected, outcomes + + +def assert_outcomes( + outcomes: Dict[str, int], + passed: int = 0, + skipped: int = 0, + failed: int = 0, + errors: int = 0, + xpassed: int = 0, + xfailed: int = 0, +) -> None: + """Assert that the specified outcomes appear with the respective + numbers (0 means it didn't occur) in the text output from a test run.""" + __tracebackhide__ = True + + obtained = { + "passed": outcomes.get("passed", 0), + "skipped": outcomes.get("skipped", 0), + "failed": outcomes.get("failed", 0), + "errors": outcomes.get("errors", 0), + "xpassed": outcomes.get("xpassed", 0), + "xfailed": outcomes.get("xfailed", 0), + } + expected = { + "passed": passed, + "skipped": skipped, + "failed": failed, + "errors": errors, + "xpassed": xpassed, + "xfailed": xfailed, + } + assert obtained == expected