diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6373e51..02e8fdd 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,15 @@ CHANGELOG ========= +UNRELEASED +---------- + +*UNRELEASED* + +* Fix ``self.instance._outcome`` is ``None`` case in #173 (`#174`_). + +.. _#174: https://github.com/pytest-dev/pytest-subtests/pull/174 + 0.14.0 ------ diff --git a/src/pytest_subtests/plugin.py b/src/pytest_subtests/plugin.py index 316e1c0..969285a 100644 --- a/src/pytest_subtests/plugin.py +++ b/src/pytest_subtests/plugin.py @@ -105,8 +105,10 @@ def _addSkip(self: TestCaseFunction, testcase: TestCase, reason: str) -> None: self.addSubTest(testcase.test_case, testcase, exc_info) # type: ignore[attr-defined] else: # For python < 3.11: the non-subtest skips have to be added by `_originaladdSkip` only after all subtest - # failures are processed by `_addSubTest`. - if sys.version_info < (3, 11): + # failures are processed by `_addSubTest`. (`self.instance._outcome` has no attribute `skipped/errors` anymore.) + # For python < 3.11, we also need to check if `self.instance._outcome` is `None` (this happens if the test + # class/method is decorated with `unittest.skip`, see #173). + if sys.version_info < (3, 11) and self.instance._outcome is not None: subtest_errors = [ x for x, y in self.instance._outcome.errors diff --git a/tests/test_subtests.py b/tests/test_subtests.py index 8ec97bf..299db77 100644 --- a/tests/test_subtests.py +++ b/tests/test_subtests.py @@ -336,6 +336,34 @@ def test_foo(self): ["collected 1 item", "* 3 xfailed, 1 passed in *"] ) + @pytest.mark.parametrize("runner", ["pytest-normal"]) + def test_only_original_skip_is_called( + self, + pytester: pytest.Pytester, + monkeypatch: pytest.MonkeyPatch, + runner: Literal["pytest-normal"], + ) -> None: + """Regression test for #173.""" + monkeypatch.setenv("COLUMNS", "200") + p = pytester.makepyfile( + """ + import unittest + from unittest import TestCase, main + + @unittest.skip("skip this test") + class T(unittest.TestCase): + def test_foo(self): + assert 1 == 2 + + if __name__ == '__main__': + main() + """ + ) + result = pytester.runpytest(p, "-v", "-rsf") + result.stdout.fnmatch_lines( + ["SKIPPED [1] test_only_original_skip_is_called.py:6: skip this test"] + ) + @pytest.mark.parametrize("runner", ["unittest", "pytest-normal", "pytest-xdist"]) def test_skip_with_failure( self,