Pourquoi Pytest : tests Python ?
Pytest est un framework de tests Python qui a vu son émergence en 2013 et qui est aujourd'hui l'un des frameworks de tests les plus populaires pour Python. Il est largement utilisé par les développeurs professionnels pour assurer la qualité de leurs applications tout au long du développement.
Dans le monde réel, un développeur doit effectuer constamment des tests pour s'assurer que son code fonctionne correctement et qu'il répond aux besoins des utilisateurs. Pytest simplifie ce processus en offrant une syntaxe intuitive, une grande flexibilité et une gamme de fonctionnalités avancées.
Par exemple, imaginez un développeur travaillant sur une application web qui prend des commandes de commande. Il doit s'assurer que chaque commande est traitée correctement, que les utilisateurs reçoivent les bons produits, et que la commande n'est pas en double. Pytest peut aider à automatiser ces tests, ce qui permet au développeur de passer plus de temps sur l'amélioration de l'application plutôt que sur le débogage.
Prerequis
Pour utiliser Pytest, il est nécessaire d'avoir les éléments suivants :
- Python : Il faut avoir Python installé sur votre machine. La version recommandée est la 3.6 ou plus tard.
- Pytest : Vous pouvez installer Pytest en utilisant pip :
pip install pytest
Concepts fondamentaux
Installation et configuration de Pytest
Pour commencer à utiliser Pytest, il suffit d'installer le package via pip comme mentionné précédemment. Une fois que Pytest est installé, vous pouvez créer un premier test simple en créant un fichier Python avec une extension .py.
## tests/test_example.py
def add(a, b):
return a + b
def test_add():
assert add(2, 3) == 5
Structure des fichiers de tests
Pytest utilise les conventions standard pour identifier les fichiers de tests. Un fichier est considéré comme un fichier de test s'il suit l'un des formats suivants :
test_*.py*_test.py
Par exemple, le fichier tests/test_example.py contient une fonction de test simple qui vérifie que la fonction add retourne la somme correcte.
Assertions
Les assertions sont un élément crucial de Pytest. Elles permettent de vérifier si une condition est vraie ou fausse. Si l'assertion échoue, Pytest affiche le message d'erreur et les détails du test qui a échoué.
## tests/test_example.py
def test_add():
assert add(2, 3) == 5 # Cette assertion passe
assert add(-1, 1) == 0 # Cette assertion passe aussi
Fixtures
Les fixtures sont des fonctions qui fournissent des données de test à vos tests. Elles permettent d'éviter la duplication de code et de factoriser les ressources nécessaires pour les tests.
## tests/test_example.py
import pytest
@pytest.fixture
def sample_data():
return [1, 2, 3, 4, 5]
def test_sum(sample_data):
assert sum(sample_data) == 15
Paramètres de test
Pytest vous permet de paramétrer vos tests pour exécuter plusieurs fois le même test avec des valeurs différentes.
## tests/test_example.py
import pytest
@pytest.mark.parametrize("a, b, expected", [
(2, 3, 5),
(-1, 1, 0),
(0, 0, 0)
])
def test_add(a, b, expected):
assert add(a, b) == expected
Mise en pratique : projet fil rouge
Mini-projet : Un gestionnaire de tâches simple
Nous allons créer un gestionnaire de tâches simple avec une interface en ligne de commande (CLI). Ce gestionnaire devra permettre d'ajouter, de lister et de supprimer des tâches.
Étape 1 : Création du projet
Créez un nouveau répertoire pour votre projet et initialisez un environnement virtuel.
mkdir todo_manager
cd todo_manager
python -m venv venv
source venv/bin/activate # Sur Windows utilisez `venv\Scripts\activate`
Étape 2 : Création des fichiers de code
Créez les fichiers suivants :
todo_manager.py: Contiendra la logique du gestionnaire de tâches.tests/test_todo_manager.py: Contiendra les tests unitaires pour la classeTodoManager.
Étape 3 : Implémentation du code
todo_manager.py
## todo_manager.py
class TodoManager:
def __init__(self):
self.tasks = []
def add_task(self, task):
self.tasks.append(task)
def list_tasks(self):
return self.tasks
def remove_task(self, index):
if 0 <= index < len(self.tasks):
del self.tasks[index]
tests/test_todo_manager.py
## tests/test_todo_manager.py
import pytest
from todo_manager import TodoManager
def test_add_task():
manager = TodoManager()
manager.add_task("Faire les courses")
assert "Faire les courses" in manager.list_tasks()
def test_list_tasks():
manager = TodoManager()
manager.add_task("Faire les courses")
manager.add_task("Passer l'aspirateur")
tasks = manager.list_tasks()
assert len(tasks) == 2
assert "Faire les courses" in tasks
assert "Passer l'aspirateur" in tasks
def test_remove_task():
manager = TodoManager()
manager.add_task("Faire les courses")
manager.add_task("Passer l'aspirateur")
manager.remove_task(0)
assert len(manager.list_tasks()) == 1
assert "Passer l'aspirateur" in manager.list_tasks()
Étape 4 : Exécution des tests
Pour exécuter les tests, utilisez la commande suivante :
pytest
Si tous les tests passent, vous verrez une sortie similaire à celle-ci :
============================= test session starts ==============================
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
rootdir: /path/to/todo_manager
collected 3 items
tests/test_todo_manager.py ..F [100%]
=================================== FAILURES ===================================
________________________________ test_remove_task _________________________________
def test_remove_task():
manager = TodoManager()
manager.add_task("Faire les courses")
manager.add_task("Passer l'aspirateur")
> manager.remove_task(3)
E IndexError: list index out of range
tests/test_todo_manager.py:14: IndexError
============================== 1 failed, 2 passed in 0.01s ===============================
Erreurs frequentes et debugging
Erreur : AttributeError: 'NoneType' object has no attribute 'tasks'
## ❌ Mauvais
def test_add_task():
manager = TodoManager()
manager.add_task("Faire les courses")
assert manager.tasks == ["Faire les courses"] # Cette assertion échoue si manager est None
## ✅ Correct
def test_add_task():
manager = TodoManager()
manager.add_task("Faire les courses")
assert "Faire les courses" in manager.list_tasks() # Utilisez list_tasks pour vérifier le contenu de tasks
Erreur : AssertionError: Expected call: add_task('Passer l'aspirateur')
## ❌ Mauvais
def test_add_task():
manager = TodoManager()
manager.add_task("Faire les courses")
with pytest.raises(Exception) as e:
manager.add_task("Passer l'aspirateur")
## ✅ Correct
def test_add_task():
manager = TodoManager()
manager.add_task("Faire les courses")
assert "Passer l'aspirateur" not in manager.list_tasks() # Vérifiez que la tâche n'est pas ajoutée
Erreur : IndexError: list index out of range
## ❌ Mauvais
def test_remove_task():
manager = TodoManager()
manager.add_task("Faire les courses")
manager.add_task("Passer l'aspirateur")
manager.remove_task(3)
## ✅ Correct
def test_remove_task():
manager = TodoManager()
manager.add_task("Faire les courses")
manager.add_task("Passer l'aspirateur")
manager.remove_task(1) # Supprime le dernier élément
Pour aller plus loin
1. Testes d'intégration
Vous pouvez utiliser Pytest pour écrire des tests d'intégration qui testent comment les différentes composantes de votre application fonctionnent ensemble.
2. Gestion des fixtures complexes
Pytest offre une grande flexibilité dans la gestion des fixtures, permettant de créer des fixtures paramétrées et de partager des ressources entre les tests.
3. Reporting avancé
Pytest dispose d'extensions qui peuvent être utilisées pour générer des rapports plus détaillés sur les résultats des tests, facilitant ainsi le suivi et l'amélioration du code.
Défi pratique
Écrivez un mini-projet de gestionnaire de blog en ligne avec les fonctionnalités suivantes :
- Ajouter un article
- Supprimer un article
- Mettre à jour un article
- Lister tous les articles
Utilisez Pytest pour écrire des tests unitaires et d'intégration pour vérifier que chaque fonctionnalité est correctement implémentée.