Comment écrire et exécuter des tests unitaires en Python à l'aide de PyTest
Lorsque vous écrivez du code en Python, il est important de vous assurer que votre code fonctionne comme prévu. L'un des meilleurs moyens d'y parvenir consiste à utiliser des tests unitaires, qui vous aident à vérifier si de petites parties (ou unités) de votre code fonctionnent correctement.
Dans cet article, nous apprendrons comment écrire et exécuter des tests unitaires efficaces en Python à l'aide de PyTest, l'un des frameworks de test les plus populaires pour Python.
Que sont les tests unitaires ?
Les tests unitaires sont de petits tests simples qui se concentrent sur la vérification d'une seule fonction ou d'un petit morceau de code. Ils permettent de garantir que votre code fonctionne comme prévu et peut détecter les bogues plus tôt.
Les tests unitaires peuvent être écrits pour différentes parties de votre code, telles que les fonctions, les méthodes et même les classes. En écrivant des tests unitaires, vous pouvez tester votre code sans exécuter l'intégralité du programme.
Pourquoi utiliser PyTest ?
PyTest est un framework de test populaire pour Python qui facilite l'écriture et l'exécution de tests.
Il est simple à utiliser et possède de nombreuses fonctionnalités utiles telles que :
- Il vous permet de rédiger des cas de tests simples et clairs.
- Il fournit des fonctionnalités avancées telles que des appareils, des tests paramétrés et des plugins.
- Il fonctionne bien avec d'autres outils de test et bibliothèques.
- Il génère des résultats de tests et des rapports faciles à lire.
Configuration de PyTest sous Linux
Avant de commencer à écrire des tests, nous devons installer PyTest. Si PyTest n'est pas installé, vous pouvez l'installer à l'aide du gestionnaire de packages Python appelé pip.
pip install pytest
Une fois PyTest installé, vous êtes prêt à commencer à écrire des tests !
Écrire votre premier test avec PyTest
Commençons par écrire une fonction simple, puis écrivons un test pour celle-ci.
Étape 1 : écrire une fonction simple
Tout d’abord, créons une fonction Python que nous souhaitons tester. Disons que nous avons une fonction qui additionne deux nombres :
# add.py
def add(a, b):
return a + b
Il s'agit d'une fonction simple qui prend deux nombres a et b, les additionne et renvoie le résultat.
Étape 2 : écrire un test pour la fonction
Maintenant, écrivons un test pour la fonction add. Dans PyTest, les tests sont écrits dans des fichiers séparés, généralement nommés test_*.py
pour faciliter l'identification des fichiers de test.
Créez un nouveau fichier appelé test_add.py
et écrivez le code de test suivant :
# test_add.py
from add import add
def test_add_numbers():
assert add(2, 3) == 5
assert add(-1, 1) == 0
assert add(0, 0) == 0
Explication du code ci-dessus :
- Nous importons la fonction
add
depuis le fichieradd.py
. - Nous définissons une fonction de test appelée
test_add_numbers()
. Dans PyTest, une fonction de test doit commencer par le mottest_
. - Dans la fonction de test, nous utilisons l'instruction
assert
pour vérifier si le résultat de l'appel de la fonctionadd
correspond à la valeur attendue. Si la condition dans l'instructionassert
estTrue
, le test réussit ; sinon, cela échoue.
Étape 3 : Exécutez le test
Pour exécuter le test, ouvrez votre terminal et accédez au répertoire où se trouve votre fichier test_add.py
, puis exécutez la commande suivante :
pytest
PyTest trouvera automatiquement tous les fichiers de test (ceux qui commencent par test_
) et exécutera les tests qu'ils contiennent. Si tout fonctionne correctement, vous devriez voir un résultat comme celui-ci :
Le point (.)
indique que le test a réussi. S'il y avait des problèmes, PyTest afficherait un message d'erreur.
Écrire des tests plus avancés
Maintenant que nous savons comment écrire et exécuter un test de base, explorons quelques fonctionnalités plus avancées de PyTest.
Test des exceptions attendues
Parfois, vous souhaitez tester si votre code génère les exceptions correctes en cas de problème. Vous pouvez le faire avec la fonction pytest.raises()
.
Disons que nous voulons tester une fonction qui divise deux nombres. Nous voulons lever une exception si le deuxième nombre est zéro (pour éviter les erreurs de division par zéro).
Voici la fonction diviser
:
# divide.py
def divide(a, b):
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b
Maintenant, écrivons un test pour cette fonction qui vérifie si la ValueError
est levée lorsque nous essayons de diviser par zéro :
# test_divide.py
from divide import divide
import pytest
def test_divide_numbers():
assert divide(10, 2) == 5
assert divide(-10, 2) == -5
assert divide(10, -2) == -5
def test_divide_by_zero():
with pytest.raises(ValueError):
divide(10, 0)
Explication du code :
- Nous avons ajouté une nouvelle fonction de test appelée
test_divide_by_zero()
. - Dans cette fonction, nous utilisons
pytest.raises(ValueError)
pour vérifier si uneValueError
est levée lorsque nous appelons la fonction de division avec zéro comme deuxième argument.
Réexécutez les tests avec la commande pytest. Si tout fonctionne correctement, vous devriez voir ce résultat :
Utilisation des appareils pour la configuration et le nettoyage
Dans certains cas, vous devrez peut-être définir certaines conditions avant d'exécuter vos tests ou effectuer un nettoyage une fois les tests terminés. PyTest fournit des appareils pour gérer cela.
Un appareil est une fonction que vous pouvez utiliser pour configurer ou supprimer les conditions de vos tests. Les appareils sont souvent utilisés pour créer des objets ou se connecter à des bases de données nécessaires aux tests.
Voici un exemple d'utilisation d'un appareil pour configurer un répertoire temporaire pour tester les opérations sur les fichiers :
# test_file_operations.py
import pytest
import os
@pytest.fixture
def temporary_directory():
temp_dir = "temp_dir"
os.mkdir(temp_dir)
yield temp_dir # This is where the test will run
os.rmdir(temp_dir) # Cleanup after the test
def test_create_file(temporary_directory):
file_path = os.path.join(temporary_directory, "test_file.txt")
with open(file_path, "w") as f:
f.write("Hello, world!")
assert os.path.exists(file_path)
Explication du code :
- Nous définissons un appareil appelé
temporary_directory
qui crée un répertoire temporaire avant le test et le supprime ensuite. - La fonction de test
test_create_file()
utilise ce luminaire pour créer un fichier dans le répertoire temporaire et vérifie si le fichier existe.
Exécutez à nouveau les tests avec la commande pytest. PyTest détectera et utilisera automatiquement l'appareil.
Paramétrez vos tests avec Pytest
Parfois, vous souhaitez exécuter le même test avec des entrées différentes. PyTest vous permet de le faire facilement en utilisant le paramétrage.
Disons que nous voulons tester notre fonction add
avec plusieurs paires de nombres. Au lieu d'écrire des fonctions de test distinctes pour chaque paire, nous pouvons utiliser pytest.mark.parametrize
pour exécuter le même test avec des entrées différentes.
# test_add.py
import pytest
from add import add
@pytest.mark.parametrize("a, b, expected", [
(2, 3, 5),
(-1, 1, 0),
(0, 0, 0),
(100, 200, 300)
])
def test_add_numbers(a, b, expected):
assert add(a, b) == expected
Explication du code :
- Nous utilisons le décorateur
pytest.mark.parametrize
pour définir plusieurs ensembles d'entrées (a
,b
etattendu
). - Le test
function test_add_numbers()
s'exécutera une fois pour chaque ensemble d'entrées.
Exécutez à nouveau les tests avec la commande pytest, qui exécutera le test quatre fois, une fois pour chaque ensemble d'entrées.
Conclusion
Dans cet article, nous avons appris comment écrire et exécuter des tests unitaires efficaces en Python à l'aide de PyTest pour détecter les bogues rapidement et garantir que votre code fonctionne comme prévu.
PyTest facilite l'écriture et l'exécution de ces tests, et grâce à ses fonctionnalités puissantes, vous pouvez gérer des besoins de tests plus complexes à mesure que vous progressez dans votre parcours Python.