summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrançois Freitag <mail@franek.fr>2020-09-06 14:36:20 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-09-07 08:07:26 +0200
commit57dadfac3cfae050c49b80c5ac56008acdef5196 (patch)
tree28dd850eb41ce19a9274f913d8c5ac117d672404
parent11ebc6479ffda87376b60c9475d33d8120f86368 (diff)
Fixed #31944 -- Used addCleanup() to register TestContextDecorator cleanups.
Cleanups from addCleanup() are scheduled to happen in reverse order to the order they are added (LIFO). Ensures each cleanup is executed from the innermost to the outermost.
-rw-r--r--django/test/utils.py13
-rw-r--r--docs/releases/3.2.txt5
-rw-r--r--tests/test_utils/tests.py23
3 files changed, 30 insertions, 11 deletions
diff --git a/django/test/utils.py b/django/test/utils.py
index 85aa7e06c0..4f4ce99967 100644
--- a/django/test/utils.py
+++ b/django/test/utils.py
@@ -351,24 +351,15 @@ class TestContextDecorator:
def decorate_class(self, cls):
if issubclass(cls, TestCase):
decorated_setUp = cls.setUp
- decorated_tearDown = cls.tearDown
def setUp(inner_self):
context = self.enable()
+ inner_self.addCleanup(self.disable)
if self.attr_name:
setattr(inner_self, self.attr_name, context)
- try:
- decorated_setUp(inner_self)
- except Exception:
- self.disable()
- raise
-
- def tearDown(inner_self):
- decorated_tearDown(inner_self)
- self.disable()
+ decorated_setUp(inner_self)
cls.setUp = setUp
- cls.tearDown = tearDown
return cls
raise TypeError('Can only decorate subclasses of unittest.TestCase')
diff --git a/docs/releases/3.2.txt b/docs/releases/3.2.txt
index cc7ea744a2..a7bd5575d1 100644
--- a/docs/releases/3.2.txt
+++ b/docs/releases/3.2.txt
@@ -484,6 +484,11 @@ Miscellaneous
* The undocumented ``django.utils.http.limited_parse_qsl()`` function is
removed. Please use :func:`urllib.parse.parse_qsl` instead.
+* ``django.test.utils.TestContextDecorator`` now uses
+ :py:meth:`~unittest.TestCase.addCleanup` so that cleanups registered in the
+ :py:meth:`~unittest.TestCase.setUp` method are called before
+ ``TestContextDecorator.disable()``.
+
.. _deprecated-features-3.2:
Features deprecated in 3.2
diff --git a/tests/test_utils/tests.py b/tests/test_utils/tests.py
index a82dadceaa..87e2f56979 100644
--- a/tests/test_utils/tests.py
+++ b/tests/test_utils/tests.py
@@ -1477,4 +1477,27 @@ class TestContextDecoratorTests(SimpleTestCase):
self.assertFalse(mock_disable.called)
with self.assertRaisesMessage(NotImplementedError, 'reraised'):
decorated_test_class.setUp()
+ decorated_test_class.doCleanups()
self.assertTrue(mock_disable.called)
+
+ def test_cleanups_run_after_tearDown(self):
+ calls = []
+
+ class SaveCallsDecorator(TestContextDecorator):
+ def enable(self):
+ calls.append('enable')
+
+ def disable(self):
+ calls.append('disable')
+
+ class AddCleanupInSetUp(unittest.TestCase):
+ def setUp(self):
+ calls.append('setUp')
+ self.addCleanup(lambda: calls.append('cleanup'))
+
+ decorator = SaveCallsDecorator()
+ decorated_test_class = decorator.__call__(AddCleanupInSetUp)()
+ decorated_test_class.setUp()
+ decorated_test_class.tearDown()
+ decorated_test_class.doCleanups()
+ self.assertEqual(calls, ['enable', 'setUp', 'cleanup', 'disable'])