89

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?

habakuk
  • 2,712
  • 2
  • 28
  • 47

4 Answers4

149

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.

Jorge Leitao
  • 19,085
  • 19
  • 85
  • 121
  • This is it. If I add the call to the base class it works again (did I mention that it worked with django 1.7 ...). I Also do not need the call to `django.setup()`any more. – habakuk Apr 16 '15 at 07:47
  • I thought i do not need `django.setup()` but i still need it in some cases, otherwise I get an exception that the model is not instantiated. – habakuk Apr 16 '15 at 08:01
  • See @seddonym's answer https://stackoverflow.com/a/32700847/266375 - you should use setUpTestData not setUpClass . – Matthew Wilcoxson Jul 16 '20 at 11:55
43

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.

seddonym
  • 16,304
  • 6
  • 66
  • 71
  • Your comment resolves the error, but where in the documentation does it mention using `TestCase.setUpTestData` instead of `TestCase.setUpClass` for Django 1.8+? – Stéphan van Biljon Jul 19 '23 at 10:00
7

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.

Matt
  • 4,815
  • 5
  • 39
  • 40
  • Following this answer could lead to problems with your teardown, where you have leftover objects and data that's otherwise not cleaned up. That can cause inconsistencies in your test suite, particularly if you run things in parallel. – Jordan Dec 20 '16 at 03:41
  • @Jordan -- Yes, if you are creating any persistent objects, you should add some actual "cleanup" code to the teardown, I agree. – Matt Dec 22 '16 at 01:51
  • This avoids the the exception by stopping the call to the code causing the exception instead of actually fixing the problem. Basically you won't get proper automatic ROLLBACKs after each test. – Tim Tisdall Apr 14 '21 at 14:03
-1

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)
Community
  • 1
  • 1
habakuk
  • 2,712
  • 2
  • 28
  • 47