diff --git a/AUTHORS b/AUTHORS index ae67fe429..378bac5a4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -36,6 +36,7 @@ Christopher Gilling Daniel Grana Daniel Hahler Daniel Nuri +Daniel Wandschneider Danielle Jenkins Dave Hunt David Díaz-Barquero diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0f6f7ad02..5dada862a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -26,7 +26,8 @@ * Properly handle exceptions in ``multiprocessing`` tasks (`#1984`_). Thanks `@adborden`_ for the report and `@nicoddemus`_ for the PR. -* +* Clean up unittest TestCase objects after tests are complete (`#1649`_). + Thanks `@d_b_w`_ for the report and PR. * @@ -38,6 +39,7 @@ .. _@okulynyak: https://github.com/okulynyak .. _@matclab: https://github.com/matclab .. _@gdyuldin: https://github.com/gdyuldin +.. _@d_b_w: https://github.com/d_b_w .. _#442: https://github.com/pytest-dev/pytest/issues/442 .. _#1976: https://github.com/pytest-dev/pytest/issues/1976 @@ -45,6 +47,7 @@ .. _#1998: https://github.com/pytest-dev/pytest/issues/1998 .. _#2004: https://github.com/pytest-dev/pytest/issues/2004 .. _#2005: https://github.com/pytest-dev/pytest/issues/2005 +.. _#1649: https://github.com/pytest-dev/pytest/issues/1649 3.0.3 diff --git a/_pytest/unittest.py b/_pytest/unittest.py index 47868f448..4355efe70 100644 --- a/_pytest/unittest.py +++ b/_pytest/unittest.py @@ -94,6 +94,9 @@ class TestCaseFunction(pytest.Function): def teardown(self): if hasattr(self._testcase, 'teardown_method'): self._testcase.teardown_method(self._obj) + # Allow garbage collection on TestCase instance attributes. + self._testcase = None + self._obj = None def startTest(self, testcase): pass diff --git a/testing/test_unittest.py b/testing/test_unittest.py index b6be95fa5..9625ae0f8 100644 --- a/testing/test_unittest.py +++ b/testing/test_unittest.py @@ -1,5 +1,6 @@ from _pytest.main import EXIT_NOTESTSCOLLECTED import pytest +import gc def test_simple_unittest(testdir): testpath = testdir.makepyfile(""" @@ -134,6 +135,28 @@ def test_teardown(testdir): assert passed == 2 assert passed + skipped + failed == 2 +def test_teardown_issue1649(testdir): + """ + Are TestCase objects cleaned up? Often unittest TestCase objects set + attributes that are large and expensive during setUp. + + The TestCase will not be cleaned up if the test fails, because it + would then exist in the stackframe. + """ + testpath = testdir.makepyfile(""" + import unittest + class TestCaseObjectsShouldBeCleanedUp(unittest.TestCase): + def setUp(self): + self.an_expensive_object = 1 + def test_demo(self): + pass + + """) + testdir.inline_run("-s", testpath) + gc.collect() + for obj in gc.get_objects(): + assert type(obj).__name__ != 'TestCaseObjectsShouldBeCleanedUp' + @pytest.mark.skipif("sys.version_info < (2,7)") def test_unittest_skip_issue148(testdir): testpath = testdir.makepyfile("""