Accueil / Blog / Métier / 2015 / How to optimize Django unit tests with setUpTestData

How to optimize Django unit tests with setUpTestData

Par Yann Fouillat — publié 25/06/2015
Learn how to improve your unit tests with Django 1.8 and its new tests initialization method: setUpTestData.
How to optimize Django unit tests with setUpTestData

Django has in in its last stable version (1.8) a new method allowing for the creation of data only once for the whole test case: setUpTestData. We improved our test from 180 seconds to 90 seconds when updating one of our project tests. We are going to see how to use this feature for new or even old tests.

Let's start with the following model:

class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)

And the following tests, written as in Django 1.7:

class PersonTest(TestCase):
    def setUp(self):
        self.alice = Person.objects.create(first_name='Alice', last_name='Smith')
        self.bob = Person.objects.create(first_name='Bob', last_name='Smith')

    def test_alice_first_name(self):
        self.assertEqual(self.alice.first_name, 'Alice')

    def test_bob_first_name(self):
        self.assertEqual(self.bob.first_name, 'Bob')

    def test_bob_first_name_modified(self):
      self.bob.first_name = 'Jack'
        self.bob.save()
        self.assertEqual(self.bob.first_name, 'Jack')

There are two requests executed before each test. Which give us a total of six requests executed just to create the data needed by the tests. setUpTestData uses the databases transaction feature and would allowed us to only execute the requests once for all tests. setUpTestData is a class method and its use is thus a bit different from setUp:

class PersonTest(TestCase):
@classmethod
    def setUpTestData(cls):
        cls.alice = Person.objects.create(first_name='Alice', last_name='Smith')
        cls.bob = Person.objects.create(first_name='Bob', last_name='Smith')

    def test_alice_first_name(self):
        self.assertEqual(self.alice.first_name, 'Alice')

    def test_bob_first_name(self):
        self.assertEqual(self.bob.first_name, 'Bob')

    def test_bob_first_name_modified(self):
      self.bob.first_name = 'Jack'
        self.bob.save()
        self.assertEqual(self.bob.first_name, 'Jack')

Creation requests will then only be executed once. But there is another issue. If we would run the tests as is, we would realize that self.bob stays modified after the test_bob_first_name_modified test. This is because self.bob is modified in memory and is never restored after the test. We can reload every object before each tests using setUp and a new feature from django 1.8: refresh_from_db.

class PersonTest(TestCase):
@classmethod
    def setUpTestData(cls):
        cls.alice = Person.objects.create(first_name='Alice', last_name='Smith')
        cls.bob = Person.objects.create(first_name='Bob', last_name='Smith')

def setUp(self):
self.alice.refresh_from_db()
        self.bob.refresh_from_db()

    def test_alice_first_name(self):
        self.assertEqual(self.alice.first_name, 'Alice')

    def test_bob_first_name(self):
        self.assertEqual(self.bob.first_name, 'Bob')

    def test_bob_first_name_modified(self):
     self.bob.first_name = 'Jack'
        self.bob.save()
        self.assertEqual(self.bob.first_name, 'Jack')

Even if there are two more requests before every test, these are read operations rather than write ones, and are thus much faster.

It's finally rather easy to use this feature, be it for new tests or old ones, allowing an important improvement in run time.

ABONNEZ-VOUS À LA NEWSLETTER !
Voir aussi
Utilisation de la vision par ordinateur pour redresser des images Utilisation de la vision par ordinateur pour redresser des images 14/05/2019

Dans un module de comparaison d'images, lorsque deux photographies ne sont pas cadrées de la même ...

Bien configurer ses tests Python avec tox et Travis Bien configurer ses tests Python avec tox et Travis 18/03/2019

Le plus difficile dans le développement des tests unitaires c'est souvent de se motiver à écrire ...

Découvrez la formation initiation au Python Scientifique Découvrez la formation initiation au Python Scientifique 24/11/2017

La formation initiation au Python scientifique vous permettra de vous initiez à la programmation ...

Formation Python à Nantes du 10 au 12 décembre Formation Python à Nantes du 10 au 12 décembre 13/11/2018

Vous êtes développeur et maîtrisez déjà un langage de programmation ? Python vous tente et ...

Formation Python initiation à Toulouse du 3 au 5 février Formation Python initiation à Toulouse du 3 au 5 février 02/01/2015

Vous êtes développeur et maîtrisez déjà un langage de programmation ? Python vous tente et ...