#29024: `TestContextDecorator` never exits if `setUp` fails in tests
-------------------------------------+-------------------------------------
Reporter: Anthony King | Owner: Shahbaj
| Sayyad
Type: Bug | Status: assigned
Component: Testing framework | Version: master
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------
Description changed by Anthony King:
Old description:
> when using `TestContextDecorator` as a class decorator, `enable` is
> called just before `Test.setUp`, and `disable` is called after
> `Test.tearDown`.
>
> unfortunately, `tearDown` is not called in the event of a failure inside
> `setUp`. This can result in unexpected behaviour.
>
> Even though this class is not documented, there are decorators that use
> it that are.
>
> example:
>
> {{{#!python
> class example_decorator(TestContextDecorator):
> some_var = False
>
> def enable(self):
> self.__class__.some_var = True
>
> def disable(self):
> self.__class__.some_var = False
>
> class Example1TestCase(TestCase):
> def test_var_is_false(self):
> # some_var will be False
> self.assertFalse(example_decorator.some_var)
>
> @example_decorator()
> class Example2TestCase(TestCase):
> def setUp(self):
> raise Exception
>
> def test_var_is_true(self):
> # won't be hit due to exception in setUp
> self.assertTrue(example_decorator.some_var)
>
> class Example3TestCase(TestCase):
> def test_var_is_false(self):
> # some_var will be True now due to no cleanup in Example2TestCase
> self.assertFalse(example_decorator.some_var)
>
> }}}
> output:
> {{{
> .EF
> ======================================================================
> ERROR: test_var_is_true (sharefile.tests.Example2TestCase)
> ----------------------------------------------------------------------
> ... Traceback
>
> ======================================================================
> FAIL: test_var_is_false (sharefile.tests.Example3TestCase)
> ----------------------------------------------------------------------
> ...
> AssertionError: True is not false
>
> Ran 3 tests in 0.007s
>
> FAILED (failures=1, errors=1)
> }}}
>
> There are 2 potential fixes here:
> - decorate `setUpClass` and `tearDownClass`
> - use `addCleanup` inside the `setUp` decorator
>
> `addCleanup` will always run, and will only ever be registered if the
> context manager was successfully enabled.
>
> It would also be useful to have this class documented, however that's out
> of scope of this ticket.
New description:
when using `TestContextDecorator` as a class decorator, `enable` is called
just before `Test.setUp`, and `disable` is called after `Test.tearDown`.
unfortunately, `tearDown` is not called in the event of a failure inside
`setUp`. This can result in unexpected behaviour.
Even though this class is not documented, there are decorators that use it
that are.
example:
{{{#!python
class example_decorator(TestContextDecorator):
some_var = False
def enable(self):
self.__class__.some_var = True
def disable(self):
self.__class__.some_var = False
class Example1TestCase(TestCase):
def test_var_is_false(self):
# some_var will be False
self.assertFalse(example_decorator.some_var)
@example_decorator()
class Example2TestCase(TestCase):
def setUp(self):
raise Exception
def test_var_is_true(self):
# won't be hit due to exception in setUp
self.assertTrue(example_decorator.some_var)
class Example3TestCase(TestCase):
def test_var_is_false(self):
# some_var will be True now due to no cleanup in Example2TestCase
self.assertFalse(example_decorator.some_var)
}}}
output:
{{{
.EF
======================================================================
ERROR: test_var_is_true (example.tests.Example2TestCase)
----------------------------------------------------------------------
... Traceback
======================================================================
FAIL: test_var_is_false (example.tests.Example3TestCase)
----------------------------------------------------------------------
...
AssertionError: True is not false
Ran 3 tests in 0.007s
FAILED (failures=1, errors=1)
}}}
There are 2 potential fixes here:
- decorate `setUpClass` and `tearDownClass`
- use `addCleanup` inside the `setUp` decorator
`addCleanup` will always run, and will only ever be registered if the
context manager was successfully enabled.
It would also be useful to have this class documented, however that's out
of scope of this ticket.
--
--
Ticket URL: <https://code.djangoproject.com/ticket/29024#comment:3>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/067.ffe8919f5834b6b810d280ed22c84fcb%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.