diff --git a/src/_pytest/skipping.py b/src/_pytest/skipping.py index 9aacfecee..c7afef5db 100644 --- a/src/_pytest/skipping.py +++ b/src/_pytest/skipping.py @@ -234,7 +234,6 @@ def evaluate_xfail_marks(item: Item) -> Optional[Xfail]: skipped_by_mark_key = StoreKey[bool]() # Saves the xfail mark evaluation. Can be refreshed during call if None. xfailed_key = StoreKey[Optional[Xfail]]() -unexpectedsuccess_key = StoreKey[str]() @hookimpl(tryfirst=True) @@ -271,15 +270,7 @@ def pytest_runtest_makereport(item: Item, call: CallInfo[None]): outcome = yield rep = outcome.get_result() xfailed = item._store.get(xfailed_key, None) - # unittest special case, see setting of unexpectedsuccess_key - if unexpectedsuccess_key in item._store and rep.when == "call": - reason = item._store[unexpectedsuccess_key] - if reason: - rep.longrepr = f"Unexpected success: {reason}" - else: - rep.longrepr = "Unexpected success" - rep.outcome = "failed" - elif item.config.option.runxfail: + if item.config.option.runxfail: pass # don't interfere elif call.excinfo and isinstance(call.excinfo.value, xfail.Exception): assert call.excinfo.value.msg is not None diff --git a/src/_pytest/unittest.py b/src/_pytest/unittest.py index 55f15efe4..cc616578b 100644 --- a/src/_pytest/unittest.py +++ b/src/_pytest/unittest.py @@ -30,10 +30,10 @@ from _pytest.python import Function from _pytest.python import PyCollector from _pytest.runner import CallInfo from _pytest.skipping import skipped_by_mark_key -from _pytest.skipping import unexpectedsuccess_key if TYPE_CHECKING: import unittest + import twisted.trial.unittest from _pytest.fixtures import _Scope @@ -273,9 +273,18 @@ class TestCaseFunction(Function): self._addexcinfo(sys.exc_info()) def addUnexpectedSuccess( - self, testcase: "unittest.TestCase", reason: str = "" + self, + testcase: "unittest.TestCase", + reason: Optional["twisted.trial.unittest.Todo"] = None, ) -> None: - self._store[unexpectedsuccess_key] = reason + msg = "Unexpected success" + if reason: + msg += f": {reason.reason}" + # Preserve unittest behaviour - fail the test. Explicitly not an XPASS. + try: + fail(msg, pytrace=False) + except fail.Exception: + self._addexcinfo(sys.exc_info()) def addSuccess(self, testcase: "unittest.TestCase") -> None: pass @@ -283,15 +292,6 @@ class TestCaseFunction(Function): def stopTest(self, testcase: "unittest.TestCase") -> None: pass - def _expecting_failure(self, test_method) -> bool: - """Return True if the given unittest method (or the entire class) is marked - with @expectedFailure.""" - expecting_failure_method = getattr( - test_method, "__unittest_expecting_failure__", False - ) - expecting_failure_class = getattr(self, "__unittest_expecting_failure__", False) - return bool(expecting_failure_class or expecting_failure_method) - def runtest(self) -> None: from _pytest.debugging import maybe_wrap_pytest_function_for_tracing diff --git a/testing/test_unittest.py b/testing/test_unittest.py index feee09286..69bafc26d 100644 --- a/testing/test_unittest.py +++ b/testing/test_unittest.py @@ -765,7 +765,8 @@ def test_unittest_expected_failure_for_failing_test_is_xfail( @pytest.mark.parametrize("runner", ["pytest", "unittest"]) def test_unittest_expected_failure_for_passing_test_is_fail( - pytester: Pytester, runner + pytester: Pytester, + runner: str, ) -> None: script = pytester.makepyfile( """ @@ -782,7 +783,11 @@ def test_unittest_expected_failure_for_passing_test_is_fail( if runner == "pytest": result = pytester.runpytest("-rxX") result.stdout.fnmatch_lines( - ["*MyTestCase*test_passing_test_is_fail*", "*1 failed*"] + [ + "*MyTestCase*test_passing_test_is_fail*", + "Unexpected success", + "*1 failed*", + ] ) else: result = pytester.runpython(script)