Report class cleanup exceptions
This commit is contained in:
parent
4eb8b6d525
commit
4e13a5fe3f
1
AUTHORS
1
AUTHORS
|
@ -101,6 +101,7 @@ Cyrus Maden
|
||||||
Damian Skrzypczak
|
Damian Skrzypczak
|
||||||
Daniel Grana
|
Daniel Grana
|
||||||
Daniel Hahler
|
Daniel Hahler
|
||||||
|
Daniel Miller
|
||||||
Daniel Nuri
|
Daniel Nuri
|
||||||
Daniel Sánchez Castelló
|
Daniel Sánchez Castelló
|
||||||
Daniel Valenzuela Zenteno
|
Daniel Valenzuela Zenteno
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Class cleanup exceptions are now reported.
|
|
@ -111,6 +111,19 @@ class UnitTestCase(Class):
|
||||||
return None
|
return None
|
||||||
cleanup = getattr(cls, "doClassCleanups", lambda: None)
|
cleanup = getattr(cls, "doClassCleanups", lambda: None)
|
||||||
|
|
||||||
|
def process_teardown_exceptions(raise_last: bool):
|
||||||
|
errors = getattr(cls, "tearDown_exceptions", None)
|
||||||
|
if not errors:
|
||||||
|
return
|
||||||
|
others = errors[:-1] if raise_last else errors
|
||||||
|
if others:
|
||||||
|
num = len(errors)
|
||||||
|
for n, (exc_type, exc, tb) in enumerate(others, start=1):
|
||||||
|
print(f"\nclass cleanup error ({n} of {num}):", file=sys.stderr)
|
||||||
|
traceback.print_exception(exc_type, exc, tb)
|
||||||
|
if raise_last:
|
||||||
|
raise errors[-1][1]
|
||||||
|
|
||||||
def unittest_setup_class_fixture(
|
def unittest_setup_class_fixture(
|
||||||
request: FixtureRequest,
|
request: FixtureRequest,
|
||||||
) -> Generator[None, None, None]:
|
) -> Generator[None, None, None]:
|
||||||
|
@ -125,6 +138,7 @@ class UnitTestCase(Class):
|
||||||
# follow this here.
|
# follow this here.
|
||||||
except Exception:
|
except Exception:
|
||||||
cleanup()
|
cleanup()
|
||||||
|
process_teardown_exceptions(raise_last=False)
|
||||||
raise
|
raise
|
||||||
yield
|
yield
|
||||||
try:
|
try:
|
||||||
|
@ -132,6 +146,7 @@ class UnitTestCase(Class):
|
||||||
teardown()
|
teardown()
|
||||||
finally:
|
finally:
|
||||||
cleanup()
|
cleanup()
|
||||||
|
process_teardown_exceptions(raise_last=True)
|
||||||
|
|
||||||
self.session._fixturemanager._register_fixture(
|
self.session._fixturemanager._register_fixture(
|
||||||
# Use a unique name to speed up lookup.
|
# Use a unique name to speed up lookup.
|
||||||
|
|
|
@ -1500,6 +1500,64 @@ def test_do_cleanups_on_teardown_failure(pytester: Pytester) -> None:
|
||||||
assert passed == 1
|
assert passed == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_class_cleanups_failure_in_setup(pytester: Pytester) -> None:
|
||||||
|
testpath = pytester.makepyfile(
|
||||||
|
"""
|
||||||
|
import unittest
|
||||||
|
class MyTestCase(unittest.TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
def cleanup(n):
|
||||||
|
raise Exception(f"fail {n}")
|
||||||
|
cls.addClassCleanup(cleanup, 2)
|
||||||
|
cls.addClassCleanup(cleanup, 1)
|
||||||
|
raise Exception("fail 0")
|
||||||
|
def test(self):
|
||||||
|
pass
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = pytester.runpytest('-s', testpath)
|
||||||
|
result.assert_outcomes(passed=0, errors=1)
|
||||||
|
result.stderr.fnmatch_lines([
|
||||||
|
'class cleanup error (1 of 2):',
|
||||||
|
'Exception: fail 1',
|
||||||
|
'class cleanup error (2 of 2):',
|
||||||
|
'Exception: fail 2',
|
||||||
|
])
|
||||||
|
result.stdout.fnmatch_lines([
|
||||||
|
'* ERROR at setup of MyTestCase.test *',
|
||||||
|
'E * Exception: fail 0',
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def test_class_cleanups_failure_in_teardown(pytester: Pytester) -> None:
|
||||||
|
testpath = pytester.makepyfile(
|
||||||
|
"""
|
||||||
|
import unittest
|
||||||
|
class MyTestCase(unittest.TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
def cleanup(n):
|
||||||
|
raise Exception(f"fail {n}")
|
||||||
|
cls.addClassCleanup(cleanup, 2)
|
||||||
|
cls.addClassCleanup(cleanup, 1)
|
||||||
|
def test(self):
|
||||||
|
pass
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = pytester.runpytest('-s', testpath)
|
||||||
|
result.assert_outcomes(passed=1, errors=1)
|
||||||
|
result.stderr.fnmatch_lines([
|
||||||
|
'class cleanup error (1 of 2):',
|
||||||
|
'Traceback *',
|
||||||
|
'Exception: fail 1',
|
||||||
|
])
|
||||||
|
result.stdout.fnmatch_lines([
|
||||||
|
'* ERROR at teardown of MyTestCase.test *',
|
||||||
|
'E * Exception: fail 2',
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
def test_traceback_pruning(pytester: Pytester) -> None:
|
def test_traceback_pruning(pytester: Pytester) -> None:
|
||||||
"""Regression test for #9610 - doesn't crash during traceback pruning."""
|
"""Regression test for #9610 - doesn't crash during traceback pruning."""
|
||||||
pytester.makepyfile(
|
pytester.makepyfile(
|
||||||
|
|
Loading…
Reference in New Issue