Skip to content

Commit a5ee3c4

Browse files
authored
Merge pull request #12370 from pytest-dev/backport-12368-to-8.2.x
[8.2.x] unittest: fix class instances no longer released on test teardown since pytest 8.2.0
2 parents 558e4fa + f7358ae commit a5ee3c4

File tree

3 files changed

+23
-17
lines changed

3 files changed

+23
-17
lines changed

Diff for: changelog/12367.bugfix.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix a regression in pytest 8.2.0 where unittest class instances (a fresh one is created for each test) were not released promptly on test teardown but only on session teardown.

Diff for: src/_pytest/unittest.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,12 @@ def setup(self) -> None:
212212
super().setup()
213213

214214
def teardown(self) -> None:
215-
super().teardown()
216215
if self._explicit_tearDown is not None:
217216
self._explicit_tearDown()
218217
self._explicit_tearDown = None
219218
self._obj = None
219+
self._instance = None
220+
super().teardown()
220221

221222
def startTest(self, testcase: "unittest.TestCase") -> None:
222223
pass

Diff for: testing/test_unittest.py

+20-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
# mypy: allow-untyped-defs
2-
import gc
32
import sys
43
from typing import List
54

@@ -192,30 +191,35 @@ def test_check(self):
192191
def test_teardown_issue1649(pytester: Pytester) -> None:
193192
"""
194193
Are TestCase objects cleaned up? Often unittest TestCase objects set
195-
attributes that are large and expensive during setUp.
194+
attributes that are large and expensive during test run or setUp.
196195
197196
The TestCase will not be cleaned up if the test fails, because it
198197
would then exist in the stackframe.
198+
199+
Regression test for #1649 (see also #12367).
199200
"""
200-
testpath = pytester.makepyfile(
201+
pytester.makepyfile(
201202
"""
202203
import unittest
203-
class TestCaseObjectsShouldBeCleanedUp(unittest.TestCase):
204-
def setUp(self):
205-
self.an_expensive_object = 1
206-
def test_demo(self):
207-
pass
204+
import gc
208205
209-
"""
206+
class TestCaseObjectsShouldBeCleanedUp(unittest.TestCase):
207+
def test_expensive(self):
208+
self.an_expensive_obj = object()
209+
210+
def test_is_it_still_alive(self):
211+
gc.collect()
212+
for obj in gc.get_objects():
213+
if type(obj).__name__ == "TestCaseObjectsShouldBeCleanedUp":
214+
assert not hasattr(obj, "an_expensive_obj")
215+
break
216+
else:
217+
assert False, "Could not find TestCaseObjectsShouldBeCleanedUp instance"
218+
"""
210219
)
211220

212-
pytester.inline_run("-s", testpath)
213-
gc.collect()
214-
215-
# Either already destroyed, or didn't run setUp.
216-
for obj in gc.get_objects():
217-
if type(obj).__name__ == "TestCaseObjectsShouldBeCleanedUp":
218-
assert not hasattr(obj, "an_expensive_obj")
221+
result = pytester.runpytest()
222+
assert result.ret == ExitCode.OK
219223

220224

221225
def test_unittest_skip_issue148(pytester: Pytester) -> None:

0 commit comments

Comments
 (0)