unittest: restore `UnitTestFunction.obj` to return unbound rather than bound method
This fixes #9610. pytest 7.0.0 (unintentionally) changed `UnitTestFunction.obj`'s' behavior to match `Function.obj`. That is probably a good thing to have, however it evidently causes some regressions as described in the issue, so restore the previous behavior for now. In the future we might want to make this change again, but with proper consideration.
This commit is contained in:
parent
bc33ba0be9
commit
d00ca3f8e5
|
@ -0,0 +1,3 @@
|
|||
Restore `UnitTestFunction.obj` to return unbound rather than bound method.
|
||||
Fixes a crash during a failed teardown in unittest TestCases with non-default `__init__`.
|
||||
Regressed in pytest 7.0.0.
|
|
@ -185,6 +185,15 @@ class TestCaseFunction(Function):
|
|||
_excinfo: Optional[List[_pytest._code.ExceptionInfo[BaseException]]] = None
|
||||
_testcase: Optional["unittest.TestCase"] = None
|
||||
|
||||
def _getobj(self):
|
||||
assert self.parent is not None
|
||||
# Unlike a regular Function in a Class, where `item.obj` returns
|
||||
# a *bound* method (attached to an instance), TestCaseFunction's
|
||||
# `obj` returns an *unbound* method (not attached to an instance).
|
||||
# This inconsistency is probably not desirable, but needs some
|
||||
# consideration before changing.
|
||||
return getattr(self.parent.obj, self.originalname) # type: ignore[attr-defined]
|
||||
|
||||
def setup(self) -> None:
|
||||
# A bound method to be called during teardown() if set (see 'runtest()').
|
||||
self._explicit_tearDown: Optional[Callable[[], None]] = None
|
||||
|
|
|
@ -1472,3 +1472,29 @@ def test_do_cleanups_on_teardown_failure(pytester: Pytester) -> None:
|
|||
passed, skipped, failed = reprec.countoutcomes()
|
||||
assert failed == 2
|
||||
assert passed == 1
|
||||
|
||||
|
||||
def test_traceback_pruning(pytester: Pytester) -> None:
|
||||
"""Regression test for #9610 - doesn't crash during traceback pruning."""
|
||||
pytester.makepyfile(
|
||||
"""
|
||||
import unittest
|
||||
|
||||
class MyTestCase(unittest.TestCase):
|
||||
def __init__(self, test_method):
|
||||
unittest.TestCase.__init__(self, test_method)
|
||||
|
||||
class TestIt(MyTestCase):
|
||||
@classmethod
|
||||
def tearDownClass(cls) -> None:
|
||||
assert False
|
||||
|
||||
def test_it(self):
|
||||
pass
|
||||
"""
|
||||
)
|
||||
reprec = pytester.inline_run()
|
||||
passed, skipped, failed = reprec.countoutcomes()
|
||||
assert passed == 1
|
||||
assert failed == 1
|
||||
assert reprec.ret == 1
|
||||
|
|
Loading…
Reference in New Issue