Django setUpTestData() vs. setUp()

PythonDjangoUnit Testing

Python Problem Overview


Django 1.8 shipped with a refactored TestCase which allows for data initialization at the class level using transactions and savepoints via the setUpTestData() method. This is in contrast to unittest's setUp() which runs before every single test method.

Question: What is the use case for setUp() in Django now that setUpTestData() exists?

I'm looking for objective, high-level answers only, as otherwise this question would be too broad for Stack Overflow.

Python Solutions


Solution 1 - Python

It's not uncommon for there to be set-up code that can't run as a class method. One notable example is the Django test client: you might not want to reuse the same client instance across tests that otherwise share much of the same data, and indeed, the client instances automatically included in subclasses of Django's SimpleTestCase are created per test method rather than for the entire class. Suppose you had a test from the pre-Django 1.8 world with a setUp method like this:

def setUp(self):
self.the_user = f.UserFactory.create()
self.the_post = f.PostFactory.create(author=self.the_user)
self.client.login(
username=self.the_user.username, password=TEST_PASSWORD
)
# ... &c.

You might tempted to modernize the test case by changing setUp to setUpTestData, slapping a @classmethod decorator on top, and changing all the selfs to cls. But that will fail with a AttributeError: type object 'MyTestCase' has no attribute 'client'! Instead, you should use setUpTestData for the shared data and setUp for the per-test-method client:

@classmethod
def setUpTestData(cls):
cls.the_user = f.UserFactory.create()
cls.the_post = f.PostFactory.create(author=cls.the_user)
# ... &c.

def setUp(self):
    self.client.login(
        username=self.the_user.username, password=TEST_PASSWORD
    )

Note: if you are wondering what that variable f is doing in the example code, it comes from factoryboy - a useful fixtures library for creating objects for your tests.

Solution 2 - Python

Taken from this testing tutorial: https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Testing#Views

setUpTestData() is called once at the beginning of the test run for class-level setup. You'd use this to create objects that aren't going to be modified or changed in any of the test methods.

setUp() is called before every test function to set up any objects that may be modified by the test (every test function will get a "fresh" version of these objects).

Solution 3 - Python

Caches issues. Even if Django gets better at providing test isolation with transaction rollback, caches are still generated and cleared manually.

[edit] : SetUpTestData defines the state the DB will be restored to after each test, and does so with a method that is executed only once, transaction rollback being done behind the curtain by Django. This does not work for caches. If you want the cache to be the same for each test, you need to reset it between each test, thus the need for setUp. Django can rollback the DB but can't rollback everything.

(Thank you bryan-oakley for the suggestion )

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionrneviusView Question on Stackoverflow
Solution 1 - PythonZack M. DavisView Answer on Stackoverflow
Solution 2 - Pythonuser2052130View Answer on Stackoverflow
Solution 3 - PythonJoachim JablonView Answer on Stackoverflow