Cours
Tutoriel sur les tests unitaires en Python
Les tests unitaires sont une méthode de test des logiciels par laquelle des unités individuelles de code source sont soumises à divers tests afin de déterminer si elles sont aptes à être utilisées. Il détermine et assure la qualité de votre code.
En général, lorsque le processus de développement est terminé, le développeur code les critères, ou les résultats qui sont connus pour être potentiellement pratiques et utiles, dans le script de test pour vérifier l'exactitude d'une unité particulière. Au cours de l'exécution des cas de test, divers cadres enregistrent les tests qui échouent à un critère quelconque et les signalent dans un résumé.
Les développeurs sont censés rédiger des scripts de test automatisés, qui garantissent que chaque section ou unité est conforme à sa conception et se comporte comme prévu.
Tests unitaires Python
Bien que l'écriture de tests manuels pour votre code soit définitivement une tâche fastidieuse et chronophage, le cadre de test unitaire intégré à Python a rendu la vie beaucoup plus facile.
Le cadre de test unitaire de Python s'appelle unittest
et est fourni avec Python.
Les tests unitaires permettent à votre code d'être à l'épreuve du temps puisque vous anticipez les cas où votre code pourrait potentiellement échouer ou produire un bogue. Bien que vous ne puissiez pas prévoir tous les cas, vous pouvez néanmoins traiter la plupart d'entre eux.
Une unité peut être classée en plusieurs catégories :
- Un module entier,
- Une fonction individuelle,
- Une interface complète comme une classe ou une méthode.
La meilleure façon d'écrire des tests unitaires pour votre code est de commencer par la plus petite unité testable que votre code puisse avoir, puis de passer à d'autres unités et de voir comment cette plus petite unité interagit avec d'autres unités, de cette façon vous pouvez construire un test unitaire complet pour vos applications.
Le cadre de test unitaire de Python a été inspiré par le cadre de test unitaire de Java ( JUnit
) et présente des caractéristiques similaires à celles des principaux cadres de test unitaire d'autres langages. Le cadre de test unitaire de Python offre diverses fonctionnalitésnotamment :
- Automatisation des tests
- Partage du code d'installation et d'arrêt pour les tests
- Agrégation des tests en collections
- Indépendance des tests par rapport au cadre de présentation des rapports
Prenons maintenant un exemple et comprenons pourquoi vous avez besoin de tester votre code à l'unité.
Premiers pas avec Python unittest
Vous trouverez ci-dessous les étapes nécessaires à l'utilisation du cadre de Python unittest
.
Création d'une fonction cube
Ecrivons un code pour calculer le volume d'un cube en Python
def cuboid_volume(l):
return (l*l*l)
length = [2,1.1, -2.5, 2j, 'two']
for i in range(len(length)):
print ("The volume of cuboid:",cuboid_volume(length[i]))
The volume of cuboid: 8
The volume of cuboid: 1.3310000000000004
The volume of cuboid: -15.625
The volume of cuboid: (-0-8j)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-7-67e1c37a435f> in <module>
1 for i in range(len(length)):
----> 2 print ("The volume of cuboid:",cuboid_volume(length[i]))
<ipython-input-2-f50464fd88da> in cuboid_volume(l)
1 def cuboid_volume(l):
----> 2 return (l*l*l)
TypeError: can't multiply sequence by non-int of type 'str'
Analyse des résultats
Le résultat ci-dessus devrait vous donner une idée de l'importance de la mise en place d'un test unitaire pour votre code. Il y a trois choses qui sont certainement incorrectes dans le code ci-dessus :
- Tout d'abord, le volume du parallélépipède est négatif,
- Deuxièmement, le volume du cuboïde est un nombre complexe,
- Enfin, le code aboutit à
TypeError
car vous ne pouvez pas multiplier une chaîne de caractères, qui n'est pas un indice.
Le troisième problème s'est heureusement soldé par une erreur, tandis que le premier et le deuxième ont réussi, bien que le volume du cuboïde ne puisse pas être négatif et qu'il s'agisse d'un nombre complexe.
Les tests unitaires sont généralement écrits sous la forme d'un code séparé dans un fichier différent, et il peut exister différentes conventions de dénomination que vous pouvez suivre. Vous pouvez écrire le nom du fichier de test unitaire sous la forme name of the code/unit + test
séparé par un trait de soulignement ou test + name of the code/unit
séparé par un trait de soulignement.
Par exemple, disons que le nom du fichier de code ci-dessus est cuboid_volume.py
, alors le nom du code de votre test unitaire pourrait être cuboid_volume_test.py
Sans plus attendre, écrivons le test unitaire pour le code ci-dessus.
Utilisation de assertAlmostEqual
Tout d'abord, créons un fichier Python avec le nom volume_cuboid.py
, qui contiendra le code de calcul du volume et le second avec le nom test_volume_cuboid.py
, qui contiendra le code de test unitaire.
importation unittest
La classe TestCuboid
hérite du module unittest
, et dans cette classe, vous définissez diverses méthodes que vous voulez que votre test unitaire vérifie avec votre fonction cuboid_volume
.
La première fonction que vous définirez est test_volume
, qui vérifiera si la sortie de votre cuboid_volume
est égale à ce que vous attendez. Pour ce faire, vous utiliserez la méthode assertAlmostEqual
.
Test 1
class TestCuboid(unittest.TestCase):
def test_volume(self):
self.assertAlmostEqual(cuboid_volume(2),8)
self.assertAlmostEqual(cuboid_volume(1),1)
self.assertAlmostEqual(cuboid_volume(0),0)
self.assertAlmostEqual(cuboid_volume(5.5),166.375)
Exécutons le script ci-dessus. Vous pouvez exécuter le module unittest
en tant que script en spécifiant -m
lors de son exécution.
!python -m unittest test_volume_cuboid.py
Sortie :
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
C'est très bien ! Vous avez donc réussi à faire fonctionner votre premier code de test unitaire.
Le test s'est déroulé avec succès et a retourné OK
, ce qui signifie que la fonction cuboid_volume fonctionne comme vous vous y attendez.
Test 2
Voyons ce qui se passe lorsque l'une des méthodes assertAlmostEqual
échoue.
Remarquez que la dernière instruction assert a été modifiée.
!python -m unittest test_volume_cuboid.py
Sortie :
F
======================================================================
FAIL: test_volume (test_volume_cuboid.TestCuboid)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\hda3kor\Documents\Unit_Testing_Python\test_volume_cuboid.py", line 15, in test_volume
self.assertAlmostEqual(cuboid_volume(5.5),0)
AssertionError: 166.375 != 0 within 7 places (166.375 difference)
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (failures=1)
D'après la sortie ci-dessus, vous pouvez observer que la dernière instruction assert a donné lieu à un AssertionError
, et donc à un échec du test unitaire. Le module de test unitaire de Python vous indique la raison de l'échec, ainsi que le nombre d'échecs de votre code.
Utilisation de assertRaises
Examinons maintenant une autre méthode d'affirmation, à savoir assertRaises
, qui vous aidera à déterminer si votre fonction cuboid_volume
traite correctement les valeurs d'entrée.
Supposons que vous souhaitiez tester si votre fonction cuboid_volume
gère la classe ou le type d'entrée. Par exemple, si vous passez une chaîne de caractères en entrée, la fonction traitera-t-elle cette entrée comme une exception ou avec une condition if, puisque la longueur du cuboïde ne peut jamais être une chaîne de caractères.
!python -m unittest test_volume_cuboid.py
Sortie :
F.
======================================================================
FAIL: test_input_value (test_volume_cuboid.TestCuboid)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\hda3kor\Documents\Unit_Testing_Python\test_volume_cuboid.py", line 17, in test_input_value
self.assertRaises(TypeError, cuboid_volume, True)
AssertionError: TypeError not raised by cuboid_volume
----------------------------------------------------------------------
Ran 2 tests in 0.001s
FAILED (failures=1)
C'est très bien ! Il est donc évident que votre code volume_cuboid.py
ne prend pas correctement en compte les données qui lui sont transmises.
Modifier la fonction cube
Ajoutons une condition dans volume_cuboid.py
pour vérifier si l'entrée ou la longueur du cuboïde est un booléen ou une chaîne de caractères et soulever une erreur.
!python -m unittest test_volume_cuboid.py
Sortie :
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s
OK
Exécution du script de test Python dans le laboratoire Jupyter
Exécutons maintenant le script de test dans le laboratoire jupyter. Pour ce faire, vous devez d'abord définir le script de test dans le laboratoire jupyter, comme indiqué ci-dessous.
# -*- coding: utf-8 -*-
"""
Created on Sat Apr 25 20:16:58 2020
@author: Aditya
"""
from volume_cuboid import *
import unittest
class TestCuboid(unittest.TestCase):
def test_volume(self):
self.assertAlmostEqual(cuboid_volume(2),8)
self.assertAlmostEqual(cuboid_volume(1),1)
self.assertAlmostEqual(cuboid_volume(0),1)
def test_input_value(self):
self.assertRaises(TypeError, cuboid_volume, True)
Ensuite, vous utiliserez la méthode unittest.main()
pour exécuter le script de test, vous pouvez passer plusieurs arguments à la méthode ci-dessous, dont l'un est verbosity level
.
Expérimentons différents niveaux de verbosité et voyons comment cela modifie la description de la sortie.
Verbosité 0
unittest.main(argv=[''],verbosity=0, exit=False)
Output:
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
<unittest.main.TestProgram at 0x1de02774348>
Verbosité 1
unittest.main(argv=[''],verbosity=1, exit=False)
Output:
..
----------------------------------------------------------------------
Ran 2 tests in 0.002s
OK
<unittest.main.TestProgram at 0x1de027a1cc8>
Verbosité 2
unittest.main(argv=[''],verbosity=2, exit=False)
Output:
test_input_value (__main__.TestCuboid) ... ok
test_volume (__main__.TestCuboid) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.002s
OK
<unittest.main.TestProgram at 0x1de027a8308>
Visualisation de l'erreur d'assertion
Enfin, modifions le site final assertAlmostEqual
dans la méthode test_volume
et analysons comment le niveau de verbosité 2 montrera l'échec de la méthode.
# -*- coding: utf-8 -*-
"""
Created on Sat Apr 25 20:16:58 2020
@author: Aditya
"""
from volume_cuboid import *
import unittest
class TestCuboid(unittest.TestCase):
def test_volume(self):
self.assertAlmostEqual(cuboid_volume(2),8)
self.assertAlmostEqual(cuboid_volume(1),1)
self.assertAlmostEqual(cuboid_volume(0),1)
def test_input_value(self):
self.assertRaises(TypeError, cuboid_volume, True)
unittest.main(argv=[''],verbosity=2, exit=False)
Sortie :
test_input_value (__main__.TestCuboid) ... ok
test_volume (__main__.TestCuboid) ... FAIL
======================================================================
FAIL: test_volume (__main__.TestCuboid)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<ipython-input-28-46ad33b909ee>", line 14, in test_volume
self.assertAlmostEqual(cuboid_volume(0),1)
AssertionError: 0 != 1 within 7 places (1 difference)
----------------------------------------------------------------------
Ran 2 tests in 0.003s
FAILED (failures=1)
<unittest.main.TestProgram at 0x1de027b5448>
Résumé
Les résultats ci-dessus permettent de tirer les conclusions suivantes :
- Le niveau de verbosité 0 indique simplement le nombre de tests effectués, c'est-à-dire 2 tests et le temps nécessaire à leur exécution,
- Niveau de verbosité 1 ajouter deux points .. ce qui signifie que deux tests ont été exécutés,
- Le niveau de verbosité 2 montre les noms détaillés des méthodes qui ont été exécutées ainsi que leur état
OK
ouFAIL
.
Méthodes d'affirmation disponibles pour unittest
Le module de test unitaire de Python contient de nombreuses méthodes d'affirmation qui peuvent être utilisées pour vos tests.
Méthodes d'affirmation couramment utilisées
Source : documentation unittest
Contrôles de production
Les méthodes suivantes vous permettent de vérifier la production d'exceptions, d'avertissements et de messages de journal.
Source : documentation unittest
Méthodes spécifiques aux tâches
Source : documentation unittest
Pour connaître en détail les méthodes de assert
, consultez la documentation officielle de Python.
Vous pouvez également apprendre à les connaître à l'aide du module Pydoc
, qui est similaire à une fonction help
en Python. Vous trouverez ci-dessous une démonstration de la manière dont vous pouvez utiliser le module Pydoc pour consulter la documentation de la méthode assertCountEqual
.
!python -m pydoc unittest.TestCase.assertCountEqual
Sortie :
Help on function assertCountEqual in unittest.TestCase:
unittest.TestCase.assertCountEqual = assertCountEqual(self, first, second, msg=None)
An unordered sequence comparison asserting that the same elements,
regardless of order. If the same element occurs more than once,
it verifies that the elements occur the same number of times.
self.assertEqual(Counter(list(first)),
Counter(list(second)))
Example:
- [0, 1, 1] and [1, 0, 1] compare equal.
- [0, 0, 1] and [0, 1] compare unequal.
Conclusion
Ce tutoriel était une introduction de base aux tests unitaires en Python et à leur importance en tant que développeur. Un bon exercice pour vous serait d'écrire un module de test unitaire pour l'un de vos anciens projets. Cela vous permettra d'acquérir une bonne expérience pratique de l'écriture de tests unitaires. Essayez également d'explorer les autres méthodes Assert. Pour en savoir plus sur les tests unitaires, consultez notre tutoriel Pytest.
Si vous débutez en Python et que vous souhaitez en savoir plus, suivez notre Introduction à la science des données en Python cours d'introduction à la science des données en Python.
Devenez développeur Python

En tant que data scientist certifié, je suis passionné par l'utilisation des technologies de pointe pour créer des applications innovantes d'apprentissage automatique. Avec une solide expérience en reconnaissance vocale, en analyse de données et en reporting, en MLOps, en IA conversationnelle et en NLP, j'ai affiné mes compétences dans le développement de systèmes intelligents qui peuvent avoir un impact réel. En plus de mon expertise technique, je suis également un communicateur compétent, doué pour distiller des concepts complexes dans un langage clair et concis. En conséquence, je suis devenu un blogueur recherché dans le domaine de la science des données, partageant mes idées et mes expériences avec une communauté grandissante de professionnels des données. Actuellement, je me concentre sur la création et l'édition de contenu, en travaillant avec de grands modèles linguistiques pour développer un contenu puissant et attrayant qui peut aider les entreprises et les particuliers à tirer le meilleur parti de leurs données.
Apprenez-en plus sur Python avec ces cours !
Cours
Python intermédiaire pour les développeurs
Cours