Reputation: 2771
I updated a Django 1.7 project to Django 1.8 and now get errors when I run the tests (that are subclasses of django.test.TestCase
).
Traceback (most recent call last):
File "env\lib\site-packages\django\test\testcases.py", line 962, in tearDownClass
cls._rollback_atomics(cls.cls_atomics)
AttributeError: type object 'SomeTests' has no attribute 'cls_atomics'
If I debug through the test I can step through all lines without problems, but after the last line the exception is thrown.
This is an example test:
import django
import unittest
from django.test import TestCase
import logging
import sys
from builtins import classmethod, isinstance
class ATestTests(TestCase):
@classmethod
def setUpClass(cls):
django.setup()
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
def setUp(self):
self._app = Application(name="a")
def testtest(self):
self.assertIsNotNone(self._app)
My environment:
astroid==1.3.4
colorama==0.3.3
defusedxml==0.4.1
Django==1.8
django-extensions==1.5.2
django-filter==0.9.2
djangorestframework==3.0.5
djangorestframework-xml==1.0.1
eight==0.3.0
future==0.11.4
logilab-common==0.63.2
Markdown==2.5.2
pylint==1.4.1
python-dateutil==2.4.1
python-mimeparse==0.1.4
six==1.9.0
xmltodict==0.9.2
How can I fix this?
Upvotes: 91
Views: 16543
Reputation: 61
For those looking for the current Django solution (Version == 5.1)
SimpleTestCase and its subclasses (e.g. TestCase, …) rely on setUpClass() and tearDownClass() to perform some class-wide initialization (e.g. overriding settings). If you need to override those methods, don’t forget to call the super implementation:
Answer: Remember to call super.setUpClass() right after def in the overriding function
@classmethod
def setUpClass(self) -> None:
super().setUpClass()
TestHelpers.setUpClass()
Other Option The answer chosen is to use setUpTestData instead of setUpClass especially if only just setting up initial test data for the TestCase
@classmethod
def setUpTestData(cls):
# Set up data for the whole TestCase
cls.foo = Foo.objects.create(bar="Test")
...
Which is also okay but
Note that if the tests are run on a database with no transaction support (for instance, MySQL with the MyISAM engine), setUpTestData() will be called before each test, negating the speed benefits.
Upvotes: 0
Reputation: 17259
For Django 1.8+, you should use TestCase.setUpTestData
instead of TestCase.setUpClass
.
class MyTests(TestCase):
@classmethod
def setUpTestData(cls):
# Set up data for the whole TestCase
cls.foo = Foo.objects.create(bar="Test")
def test1(self):
self.assertEqual(self.foo.bar, 'Test')
The documentation is here.
Upvotes: 47
Reputation: 4999
I had a similar problem where a TestCase
used setUpClass
but did not have a tearDownClass
method. My tests pass when I add an empty one:
@classmethod
def tearDownClass(cls):
pass
I also do not call django.setup
.
Upvotes: 7
Reputation: 2771
Here is the complete code with the call to the base class (as suggested by @J. C. Leitão):
import django
import unittest
from django.test import TestCase
import logging
import sys
from builtins import classmethod
class ATestTests(TestCase):
@classmethod
def setUpClass(cls):
super(ATestTests, cls).setUpClass()
django.setup()
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
def setUp(self):
self._app = Application(name="a")
def testtest(self):
self.assertIsNotNone(self._app)
Upvotes: 0
Reputation: 20173
I believe the reason is that your setUpClass(cls)
class method is not calling super. Because of that, django.tests.TestCase.setUpClass
is not called and
cls.cls_atomics = cls._enter_atomics()
is not called, naturally causing cls_atomics
to be undefined.
You should add super(ATestTests, cls).setUpClass()
to your setUpClass
.
Upvotes: 159