92

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?

8
  • Can you paste here a pip freeze? Commented Apr 15, 2015 at 14:49
  • @lapinkoira done that Commented Apr 15, 2015 at 14:53
  • 1
    mmm can I see the test implementation you run? Commented Apr 15, 2015 at 15:02
  • @lapinkoira I added more details Commented Apr 15, 2015 at 15:08
  • Do you still need this? "# Django 1.7 requires an explicit setup() when running tests in PTVS" Commented Apr 15, 2015 at 15:18

5 Answers 5

160

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.

Sign up to request clarification or add additional context in comments.

3 Comments

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.
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.
See @seddonym's answer stackoverflow.com/a/32700847/266375 - you should use setUpTestData not setUpClass .
48

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.

1 Comment

Your comment resolves the error, but where in the documentation does it mention using TestCase.setUpTestData instead of TestCase.setUpClass for Django 1.8+?
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.

3 Comments

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 -- Yes, if you are creating any persistent objects, you should add some actual "cleanup" code to the teardown, I agree.
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.
0

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)

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.