Call Python 3.8 doClassCleanups (#8033)
This commit is contained in:
parent
b7ba76653d
commit
eda681af2b
1
AUTHORS
1
AUTHORS
|
@ -232,6 +232,7 @@ Pauli Virtanen
|
||||||
Pavel Karateev
|
Pavel Karateev
|
||||||
Paweł Adamczak
|
Paweł Adamczak
|
||||||
Pedro Algarvio
|
Pedro Algarvio
|
||||||
|
Petter Strandmark
|
||||||
Philipp Loose
|
Philipp Loose
|
||||||
Pieter Mulder
|
Pieter Mulder
|
||||||
Piotr Banaszkiewicz
|
Piotr Banaszkiewicz
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
`doClassCleanups` (introduced in `unittest` in Python and 3.8) is now called.
|
|
@ -99,26 +99,48 @@ class UnitTestCase(Class):
|
||||||
"""Injects a hidden auto-use fixture to invoke setUpClass/setup_method and corresponding
|
"""Injects a hidden auto-use fixture to invoke setUpClass/setup_method and corresponding
|
||||||
teardown functions (#517)."""
|
teardown functions (#517)."""
|
||||||
class_fixture = _make_xunit_fixture(
|
class_fixture = _make_xunit_fixture(
|
||||||
cls, "setUpClass", "tearDownClass", scope="class", pass_self=False
|
cls,
|
||||||
|
"setUpClass",
|
||||||
|
"tearDownClass",
|
||||||
|
"doClassCleanups",
|
||||||
|
scope="class",
|
||||||
|
pass_self=False,
|
||||||
)
|
)
|
||||||
if class_fixture:
|
if class_fixture:
|
||||||
cls.__pytest_class_setup = class_fixture # type: ignore[attr-defined]
|
cls.__pytest_class_setup = class_fixture # type: ignore[attr-defined]
|
||||||
|
|
||||||
method_fixture = _make_xunit_fixture(
|
method_fixture = _make_xunit_fixture(
|
||||||
cls, "setup_method", "teardown_method", scope="function", pass_self=True
|
cls,
|
||||||
|
"setup_method",
|
||||||
|
"teardown_method",
|
||||||
|
None,
|
||||||
|
scope="function",
|
||||||
|
pass_self=True,
|
||||||
)
|
)
|
||||||
if method_fixture:
|
if method_fixture:
|
||||||
cls.__pytest_method_setup = method_fixture # type: ignore[attr-defined]
|
cls.__pytest_method_setup = method_fixture # type: ignore[attr-defined]
|
||||||
|
|
||||||
|
|
||||||
def _make_xunit_fixture(
|
def _make_xunit_fixture(
|
||||||
obj: type, setup_name: str, teardown_name: str, scope: "_Scope", pass_self: bool
|
obj: type,
|
||||||
|
setup_name: str,
|
||||||
|
teardown_name: str,
|
||||||
|
cleanup_name: Optional[str],
|
||||||
|
scope: "_Scope",
|
||||||
|
pass_self: bool,
|
||||||
):
|
):
|
||||||
setup = getattr(obj, setup_name, None)
|
setup = getattr(obj, setup_name, None)
|
||||||
teardown = getattr(obj, teardown_name, None)
|
teardown = getattr(obj, teardown_name, None)
|
||||||
if setup is None and teardown is None:
|
if setup is None and teardown is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
if cleanup_name:
|
||||||
|
cleanup = getattr(obj, cleanup_name, lambda *args: None)
|
||||||
|
else:
|
||||||
|
|
||||||
|
def cleanup(*args):
|
||||||
|
pass
|
||||||
|
|
||||||
@pytest.fixture(
|
@pytest.fixture(
|
||||||
scope=scope,
|
scope=scope,
|
||||||
autouse=True,
|
autouse=True,
|
||||||
|
@ -130,16 +152,32 @@ def _make_xunit_fixture(
|
||||||
reason = self.__unittest_skip_why__
|
reason = self.__unittest_skip_why__
|
||||||
pytest.skip(reason)
|
pytest.skip(reason)
|
||||||
if setup is not None:
|
if setup is not None:
|
||||||
if pass_self:
|
try:
|
||||||
setup(self, request.function)
|
if pass_self:
|
||||||
else:
|
setup(self, request.function)
|
||||||
setup()
|
else:
|
||||||
|
setup()
|
||||||
|
# unittest does not call the cleanup function for every BaseException, so we
|
||||||
|
# follow this here.
|
||||||
|
except Exception:
|
||||||
|
if pass_self:
|
||||||
|
cleanup(self)
|
||||||
|
else:
|
||||||
|
cleanup()
|
||||||
|
|
||||||
|
raise
|
||||||
yield
|
yield
|
||||||
if teardown is not None:
|
try:
|
||||||
|
if teardown is not None:
|
||||||
|
if pass_self:
|
||||||
|
teardown(self, request.function)
|
||||||
|
else:
|
||||||
|
teardown()
|
||||||
|
finally:
|
||||||
if pass_self:
|
if pass_self:
|
||||||
teardown(self, request.function)
|
cleanup(self)
|
||||||
else:
|
else:
|
||||||
teardown()
|
cleanup()
|
||||||
|
|
||||||
return fixture
|
return fixture
|
||||||
|
|
||||||
|
|
|
@ -1260,3 +1260,163 @@ def test_plain_unittest_does_not_support_async(testdir):
|
||||||
"*1 passed*",
|
"*1 passed*",
|
||||||
]
|
]
|
||||||
result.stdout.fnmatch_lines(expected_lines)
|
result.stdout.fnmatch_lines(expected_lines)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
sys.version_info < (3, 8), reason="Feature introduced in Python 3.8"
|
||||||
|
)
|
||||||
|
def test_do_class_cleanups_on_success(testdir):
|
||||||
|
testpath = testdir.makepyfile(
|
||||||
|
"""
|
||||||
|
import unittest
|
||||||
|
class MyTestCase(unittest.TestCase):
|
||||||
|
values = []
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
def cleanup():
|
||||||
|
cls.values.append(1)
|
||||||
|
cls.addClassCleanup(cleanup)
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_two(self):
|
||||||
|
pass
|
||||||
|
def test_cleanup_called_exactly_once():
|
||||||
|
assert MyTestCase.values == [1]
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
reprec = testdir.inline_run(testpath)
|
||||||
|
passed, skipped, failed = reprec.countoutcomes()
|
||||||
|
assert failed == 0
|
||||||
|
assert passed == 3
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
sys.version_info < (3, 8), reason="Feature introduced in Python 3.8"
|
||||||
|
)
|
||||||
|
def test_do_class_cleanups_on_setupclass_failure(testdir):
|
||||||
|
testpath = testdir.makepyfile(
|
||||||
|
"""
|
||||||
|
import unittest
|
||||||
|
class MyTestCase(unittest.TestCase):
|
||||||
|
values = []
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
def cleanup():
|
||||||
|
cls.values.append(1)
|
||||||
|
cls.addClassCleanup(cleanup)
|
||||||
|
assert False
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_cleanup_called_exactly_once():
|
||||||
|
assert MyTestCase.values == [1]
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
reprec = testdir.inline_run(testpath)
|
||||||
|
passed, skipped, failed = reprec.countoutcomes()
|
||||||
|
assert failed == 1
|
||||||
|
assert passed == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
sys.version_info < (3, 8), reason="Feature introduced in Python 3.8"
|
||||||
|
)
|
||||||
|
def test_do_class_cleanups_on_teardownclass_failure(testdir):
|
||||||
|
testpath = testdir.makepyfile(
|
||||||
|
"""
|
||||||
|
import unittest
|
||||||
|
class MyTestCase(unittest.TestCase):
|
||||||
|
values = []
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
def cleanup():
|
||||||
|
cls.values.append(1)
|
||||||
|
cls.addClassCleanup(cleanup)
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
assert False
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_two(self):
|
||||||
|
pass
|
||||||
|
def test_cleanup_called_exactly_once():
|
||||||
|
assert MyTestCase.values == [1]
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
reprec = testdir.inline_run(testpath)
|
||||||
|
passed, skipped, failed = reprec.countoutcomes()
|
||||||
|
assert passed == 3
|
||||||
|
|
||||||
|
|
||||||
|
def test_do_cleanups_on_success(testdir):
|
||||||
|
testpath = testdir.makepyfile(
|
||||||
|
"""
|
||||||
|
import unittest
|
||||||
|
class MyTestCase(unittest.TestCase):
|
||||||
|
values = []
|
||||||
|
def setUp(self):
|
||||||
|
def cleanup():
|
||||||
|
self.values.append(1)
|
||||||
|
self.addCleanup(cleanup)
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_two(self):
|
||||||
|
pass
|
||||||
|
def test_cleanup_called_the_right_number_of_times():
|
||||||
|
assert MyTestCase.values == [1, 1]
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
reprec = testdir.inline_run(testpath)
|
||||||
|
passed, skipped, failed = reprec.countoutcomes()
|
||||||
|
assert failed == 0
|
||||||
|
assert passed == 3
|
||||||
|
|
||||||
|
|
||||||
|
def test_do_cleanups_on_setup_failure(testdir):
|
||||||
|
testpath = testdir.makepyfile(
|
||||||
|
"""
|
||||||
|
import unittest
|
||||||
|
class MyTestCase(unittest.TestCase):
|
||||||
|
values = []
|
||||||
|
def setUp(self):
|
||||||
|
def cleanup():
|
||||||
|
self.values.append(1)
|
||||||
|
self.addCleanup(cleanup)
|
||||||
|
assert False
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_two(self):
|
||||||
|
pass
|
||||||
|
def test_cleanup_called_the_right_number_of_times():
|
||||||
|
assert MyTestCase.values == [1, 1]
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
reprec = testdir.inline_run(testpath)
|
||||||
|
passed, skipped, failed = reprec.countoutcomes()
|
||||||
|
assert failed == 2
|
||||||
|
assert passed == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_do_cleanups_on_teardown_failure(testdir):
|
||||||
|
testpath = testdir.makepyfile(
|
||||||
|
"""
|
||||||
|
import unittest
|
||||||
|
class MyTestCase(unittest.TestCase):
|
||||||
|
values = []
|
||||||
|
def setUp(self):
|
||||||
|
def cleanup():
|
||||||
|
self.values.append(1)
|
||||||
|
self.addCleanup(cleanup)
|
||||||
|
def tearDown(self):
|
||||||
|
assert False
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_two(self):
|
||||||
|
pass
|
||||||
|
def test_cleanup_called_the_right_number_of_times():
|
||||||
|
assert MyTestCase.values == [1, 1]
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
reprec = testdir.inline_run(testpath)
|
||||||
|
passed, skipped, failed = reprec.countoutcomes()
|
||||||
|
assert failed == 2
|
||||||
|
assert passed == 1
|
||||||
|
|
Loading…
Reference in New Issue