Makina Blog
Optimiser ses tests unitaires Django avec setUpTestData
Découvrez comment gagner en efficacité sur les tests unitaires et sa méthode d'initialisation des tests : setUpTestData.
Django intègre une méthode permettant de créer les données une seul fois pour tout une série de tests : setUpTestData. Nous avons ainsi pu passer de 180 secondes à 90 secondes en mettant nos tests à jours sur un de nos projet. Nous allons voir ici comment utiliser et mettre en place cette fonctionnalité sur de nouveaux tests ou même des tests déjà existants.
Partons du modèle suivant :
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
Et des tests suivants :
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')
Nous avons donc deux requêtes exécutées avant chaque test. Ce qui nous fais un total de six requêtes effectuées juste pour créer les donnés nécessaires aux tests. setUpTestData utilise les fonctionnalités des transactions des bases de données et nous permettrais de n'exécuter les requêtes qu'une seul fois pour tout les tests. setUpTestData est une méthode de classe et son utilisation est donc un peu différente de 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')
Les requêtes de création ne seront donc désormais exécutées qu'une seul fois. Mais il reste un autre problème si vous utilisez une version de Django plus ancienne que la 3.2. Si nous faisons tourner les tests tels quels, nous nous rendrions compte que self.bob reste modifié après le test test_bob_first_name_modified. Ceci est du au fait que l'objet self.bob est modifié en mémoire et n'est pas restauré après le test (ce qui est fait automatiquement à partir de Django 3.2). Nous pouvons faire en sorte de recharger les objet avant chaque test à l'aide de setUp et d'une autre fonctionnalité de Django : 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')
Même si cela fait deux requêtes en plus à chaque test, ce sont des opérations de lecture et non d'écriture, et donc beaucoup plus rapide.
Il est finalement très simple de mettre en place cette nouvelle fonctionnalité, que ce soit pour de nouveaux tests ou d'anciens, permettant un gain de temps assez important.
Actualités en lien
Makina Corpus est sponsor de la PyConFR 2024
Le soutien de Makina Corpus à la PyConFR 2024, qui se tient du 31 octobre au 3 novembre 2024 à Strasbourg, reflète ses valeurs de partage et d’innovation, et son engagement envers la communauté dynamique et ouverte de Python.
Revoir les webinaires : découverte de l’outil CANARI-France
L’application CANARI-France est destiné aux acteurs agricoles afin de calculer des indicateurs agro-climatiques à partir de projections climatiques. Découvrer en le replay des 4 webinaires organisés par Solagro et l’ADEME.
Utiliser des fonctions PostgreSQL dans des contraintes Django
Cet article vous présente comment utiliser les fonctions et les check constraints
PostgreSQL en tant que contrainte sur vos modèles Django.