AmagicalFishy
AmagicalFishy

Reputation: 1389

Django unit testing: Separating unit tests without querying the database multiple times

I have a pair of tests like this:

Make sure a task's deletion status initializes as None

def test_initial_task_deletion_status_is_none(self):
    unfinished_task = Task.objects.get(tasked_with="Unfinished Test")
    self.assertIsNone(unfinished_task.delete_status)

# Make sure a task's deletion status changes appropriately
def test_unfinished_task_deletion_status_updates_appropriately(self):
    unfinished_task = Task.objects.get(tasked_with="Unfinished Test")
    unfinished_task.timed_delete(delta=.1)
    self.assertIs(unfinished_task.delete_status, "Marked for Deletion")

This will go on, but I'll have unfinished_task = Task.objects.get(tasked_with="Unfinished Test") at the beginning of every one. Is there a way to split these types of things into separate tests, but use the same query result?

Upvotes: 1

Views: 43

Answers (2)

Daniel Hawkins
Daniel Hawkins

Reputation: 1165

You can place the repeated line in the setUp method, and that will make your code less repetitive, but as DanielRoseman pointed out, it will still be run for each test, so you won't be using the same query result.

You can place it in the setUpTestData method, and it will be run only once, before all the tests in MyTestCase, but then your unfinished_task object will be a class variable, shared across all the tests. In-memory modifications made to the object during one test will carry over into subsequent tests, and that is not what you want.

In read-only tests, using setUpTestData is a good way to cut out unnecessary queries, but if you're going to be modifying the objects, you'll want to start fresh each time.

Upvotes: 1

dhui
dhui

Reputation: 522

Assuming you're using Django's testing framework, then you can do this using setUp(). More about unittest.TestCase.setUp() here

So your updated snippet would look like:

from django.test import TestCase

class MyTestCase(TestCase):
    def setUp(self):
        self.unfinished_task = Task.objects.get(tasked_with="Unfinished Test")

    def test_initial_task_deletion_status_is_none(self): 
        self.assertIsNone(self.unfinished_task.delete_status)

    # Make sure a task's deletion status changes appropriately
    def test_unfinished_task_deletion_status_updates_appropriately(self):
        self.unfinished_task.timed_delete(delta=.1)
        self.assertIs(self.unfinished_task.delete_status, "Marked for Deletion")

Upvotes: 1

Related Questions