Lors de la création d'une application Django, un fichier tests.py est automatiquement généré.
La plupart des développeurs se posent un jour cette question.
“Ce fichier… je peux le supprimer, non ?”
“Mais comment devrais-je l’utiliser ?”
En réalité, tests.py est le point d'entrée de test officiellement recommandé par Django et,
une fois que vous y avez pris un peu de goût, il devient une véritable grande assurance lors des refactorisations, des ajouts de fonctionnalités et des mises à niveau de versions. (Django Project)
Dans cet article, nous allons aborder :
-
À quoi sert le fichier
tests.py -
Comment le rédiger et l'exécuter
-
Dans quelles situations il est particulièrement utile
-
Exemples d'utilisation pratique
nous allons tout résumer en une seule fois.
1. Quel est le fichier tests.py ?
Django utilise un framework de test basé sur unittest, la bibliothèque standard Python.
-
Vous créez des classes de tests qui héritent de
django.test.TestCase, -
vous rédigez des méthodes commençant par
test_, -
et il les trouve et les exécute automatiquement avec la commande
./manage.py test.
Lorsque vous créez une application avec startapp, un fichier tests.py est créé par défaut :
-
Pour les petits projets → un seul
tests.pysuffit -
Pour les plus grands projets → Django recommande également de diviser en un package
tests/(test_models.py,test_views.py, etc.).
C'est-à-dire, nous pouvons le considérer comme “le lieu de base pour les tests au niveau de l'application”.
2. Quand est-il utile ? (Pourquoi devrions-nous utiliser des tests ?)
Les tests Django brillent notamment dans les situations suivantes.
-
Validation des modèles/logiques métier
-
Plus la logique de calcul, les modifications d'état et les méthodes personnalisées sont complexes,
-
plus vous pouvez être sûr d'effectuer des refactorisations sans souci après avoir créé un test.
-
-
Tests de vue/URL/contrôle des droits
-
Vérifier si le code de réponse change selon l'état d'authentification
-
Vérifier si la redirection/gestion d’erreurs est adéquate en cas de saisie incorrecte
-
Vérifier si le contexte nécessaire au modèle est correctement passé
-
-
Prévention des bugs de régression
- Une fois le bug résolu, conservez-le dans un test pour éviter que le même problème ne se reproduise
-
Assurer la stabilité lors des mises à niveau de version
-
Lorsque vous augmentez la version de Django ou d'une bibliothèque
-
vous pouvez exécuter
./manage.py testpour commencer.
-
3. Exemple de base de tests.py
3-1. Test de modèle
# myapp/tests.py
from django.test import TestCase
from .models import Article
class ArticleModelTests(TestCase):
def setUp(self):
self.article = Article.objects.create(
title="Titre de test",
content="Contenu",
views=0,
)
def test_increase_views(self):
# given
self.assertEqual(self.article.views, 0)
# when
self.article.increase_views()
# then
self.assertEqual(self.article.views, 1)
-
TestCaseest une classe conçue pour Django qui étendunittest.TestCase. -
Chaque test est isolé au niveau de la transaction et, pour chaque test, la base de données est annulée pour éviter toute interférence.
4. Comment tester les vues/URL - Utiliser Client
Django fournit un client HTTP dédié aux tests django.test.Client.
Vous pouvez envoyer des requêtes GET/POST à toutes les URL sans démarrer le serveur réel.
4-1. Test d'une vue simple
# myapp/tests.py
from django.test import TestCase
from django.urls import reverse
from .models import Article
class ArticleViewTests(TestCase):
def setUp(self):
self.article = Article.objects.create(
title="Article 1",
content="Contenu",
views=0,
)
def test_article_detail_page_returns_200(self):
url = reverse("article_detail", args=[self.article.id])
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Article 1")
Les points clés ici sont :
-
self.client: une instance de client de test fournie par défaut dansTestCase -
reverse("article_detail", args=[...]): recherche par nom d'URL au lieu de hardcoder l'URL -
assertContains: vérifie si une chaîne spécifique est incluse dans le corps de la réponse
4-2. Test de connexion/vérification des droits
from django.contrib.auth import get_user_model
class ArticlePermissionTests(TestCase):
def setUp(self):
self.user = get_user_model().objects.create_user(
username="tester",
password="pass1234",
)
self.article = Article.objects.create(
title="secret",
content="Contenu secret",
views=0,
)
def test_anonymous_user_redirected_to_login(self):
url = reverse("article_edit", args=[self.article.id])
response = self.client.get(url)
self.assertEqual(response.status_code, 302)
self.assertIn("/accounts/login", response["Location"])
def test_logged_in_user_can_access_edit_page(self):
self.client.login(username="tester", password="pass1234")
url = reverse("article_edit", args=[self.article.id])
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
-
Vérifiez si un utilisateur anonyme est redirigé
-
Vérifiez si un utilisateur connecté peut accéder normalement
Vous pouvez initialement détecter les bugs liés aux autorisations.
5. Quand et comment exécuter tests.py ?
5-1. Exécution de tous les tests
$ python manage.py test
- Il cherchera automatiquement et exécutera les fichiers
test*.pysous le répertoire actuel
unittest.TestCaseou sous-classe dedjango.test.TestCase.
5-2. Exécution d'une application spécifique
$ python manage.py test myapp
5-3. Exécution d'un module/classe/méthode spécifique
# Module complet myapp.tests
$ python manage.py test myapp.tests
# Cas de test spécifique
$ python manage.py test myapp.tests.ArticleViewTests
# Méthode de test spécifique
$ python manage.py test myapp.tests.ArticleViewTests.test_article_detail_page_returns_200
Il est bon d'adopter l'habitude de tester rapidement uniquement les parties modifiées pendant le développement.
6. Étendre tests.py en un package tests
À mesure que le projet grandit, un seul tests.py devient insuffisant.
Django recommande également de le diviser en structure de package dans sa documentation. (Django Project)
Par exemple :
myapp/
tests/
__init__.py
test_models.py
test_views.py
test_forms.py
test_api.py
À l'intérieur de chaque fichier :
# myapp/tests/test_models.py
from django.test import TestCase
from myapp.models import Article
class ArticleModelTests(TestCase):
...
Il est possible de les organiser ainsi et l'exécution reste la même.
$ python manage.py test myapp # tout
$ python manage.py test myapp.tests.test_models # uniquement les tests de modèle
7. Quelques cas d'utilisation pratiques
7-1. Prévenir les régressions avec des tests de reproduction des bugs
-
Un bug se produit en production
-
Écrire un test de reproduction localement (il devrait échouer normalement)
-
Modifier le code
-
Vérifier que le test réussit
-
Committez avec
gità la fois le test et le code modifié
Cela empêchera des bugs similaires de réapparaître lors de futurs refactorisations.
7-2. Fixer le format de réponse API
Lors des collaborations avec le frontend, le format de la réponse API est très important.
class ArticleApiTests(TestCase):
def setUp(self):
self.article = Article.objects.create(
title="Titre API",
content="Contenu",
views=0,
)
def test_article_detail_api_response(self):
url = reverse("api:article-detail", args=[self.article.id])
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
data = response.json()
self.assertEqual(data["id"], self.article.id)
self.assertIn("title", data)
self.assertIn("content", data)
-
Précisez quels champs doivent absolument être inclus dans la réponse
-
Changer ou supprimer des noms de champ par erreur entraîne une échec immédiat du test
7-3. Tester la logique de validation des formulaires
from .forms import ArticleForm
class ArticleFormTests(TestCase):
def test_title_is_required(self):
form = ArticleForm(data={"title": "", "content": "Contenu"})
self.assertFalse(form.is_valid())
self.assertIn("title", form.errors)
def test_valid_form(self):
form = ArticleForm(data={"title": "Titre", "content": "Contenu"})
self.assertTrue(form.is_valid())
- Vous pouvez conserver les règles de validation du formulaire sous forme de tests comme document.

8. Conclusion - Ne supprimez pas tests.py, essayez de bien l'utiliser une fois
Pour résumer :
Le fichier
tests.pyest “le filet de sécurité d'une application Django”.
-
Au début, cela peut sembler ennuyeux, mais
-
une fois que vous aurez goûté à un flux de développement basé sur des tests,
-
le stress lors des refactorisations, des ajouts de fonctionnalités et des mises à niveau de versions diminuera considérablement.
Dans les projets réels :
-
Lorsque vous ajoutez une nouvelle fonctionnalité – ajoutez au moins 1 ou 2 tests en même temps
-
Lorsque vous corrigez un bug – commencez toujours par écrire un test qui reproduit ce bug
-
Lorsque vous commencez à augmenter le projet – refactorisez
tests.pyen un packagetests/
Suivre ce modèle vous offrira une expérience de développement complètement différente de celle d'un “projet Django sans tests”.
Aucun commentaire.