Comment utiliser PyTest pour les tests unitaires en Python

Lorsque vous écrivez du code en Python, il est important de s’assurer que votre code fonctionne comme prévu. L’un des meilleurs moyens de le faire est d’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 allons apprendre à écrire et à exécuter des tests unitaires efficaces en Python en utilisant PyTest, l’un des frameworks de test les plus populaires pour Python.

Qu’est-ce que 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 aident à garantir que votre code fonctionne comme prévu et peuvent détecter les bugs tôt.

Des tests unitaires peuvent être écrits pour différentes parties de votre code, telles que des fonctions, des méthodes et même des classes. En écrivant des tests unitaires, vous pouvez tester votre code sans exécuter l’ensemble 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 d’écrire des cas de test simples et clairs.
  • Il fournit des fonctionnalités avancées comme les fixtures, les tests paramétrés et les plugins.
  • Il fonctionne bien avec d’autres outils et bibliothèques de test.
  • Il génère des résultats de test et des rapports faciles à lire.

Configurer PyTest sous Linux

Avant de commencer à écrire des tests, nous devons installer PyTest. Si vous n’avez pas PyTest installé, vous pouvez l’installer en utilisant le gestionnaire de paquets Python appelé pip.

pip install pytest

Une fois que PyTest est installé, vous êtes prêt à commencer à écrire des tests !

Écrire votre premier test avec PyTest

Commençons par écrire une fonction simple et ensuite écrire un test pour celle-ci.

Étape 1 : Écrire une fonction simple

Tout d’abord, créons une fonction Python que nous voulons tester. Disons que nous avons une fonction qui additionne deux nombres :

# add.py
def add(a, b):
    return a + b

C’est 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 d’addition. 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 fichier add.py.
  • Nous définissons une fonction de test appelée test_add_numbers(). Dans PyTest, une fonction de test doit commencer par le mot test_.
  • À l’intérieur de la fonction de test, nous utilisons l’instruction assert pour vérifier si le résultat de l’appel de la fonction add correspond à la valeur attendue. Si la condition dans l’instruction assert est True, le test réussit ; sinon, il échoue.

Étape 3 : Exécuter le Test

Pour exécuter le test, ouvrez votre terminal et naviguez jusqu’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 à l’intérieur. Si tout fonctionne correctement, vous devriez voir une sortie comme celle-ci :

Verifying Python Code Functionality

Le point (.) indique que le test a réussi. S’il y a des problèmes, PyTest affichera 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.

Tester les Exceptions Attenues

Parfois, vous voulez tester si votre code lève les exceptions correctes lorsque quelque chose ne va pas. 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 divide :

# 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 le ValueError est levé 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().
  • À l’intérieur de cette fonction, nous utilisons pytest.raises(ValueError) pour vérifier si une ValueError est levée lorsque nous appelons la fonction de division avec zéro comme deuxième argument.

Exécutez les tests à nouveau avec la commande pytest. Si tout fonctionne correctement, vous devriez voir cette sortie :

Test Your Code with PyTest

Utilisation de fixtures pour la configuration et le nettoyage

Dans certains cas, vous devrez peut-être établir certaines conditions avant d’exécuter vos tests ou nettoyer après que les tests soient terminés. PyTest fournit des fixtures pour gérer cela.

Une fixture est une fonction que vous pouvez utiliser pour configurer ou démonter des conditions pour vos tests. Les fixtures sont souvent utilisées pour créer des objets ou se connecter à des bases de données nécessaires aux tests.

Voici un exemple d’utilisation d’une fixture pour configurer un répertoire temporaire pour tester les opérations de 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 une fixture appelée temporary_directory qui crée un répertoire temporaire avant le test et le supprime ensuite.
  • La fonction de test test_create_file() utilise cette fixture pour créer un fichier dans le répertoire temporaire et vérifie si le fichier existe.

Exécutez les tests à nouveau avec la commande pytest. PyTest détectera et utilisera automatiquement la fixture.

Paramétrer vos tests avec Pytest

Parfois, vous souhaitez exécuter le même test avec différentes entrées. PyTest vous permet de le faire facilement en utilisant parametrize.

Disons que nous voulons tester notre fonction add avec plusieurs paires de nombres. Au lieu d’écrire des fonctions de test séparées pour chaque paire, nous pouvons utiliser pytest.mark.parametrize pour exécuter le même test avec différentes entrées.

# 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 et expected).
  • Le test function test_add_numbers() sera exécuté 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 à écrire et à exécuter des tests unitaires efficaces en Python en utilisant PyTest pour détecter les bogues tôt et garantir que votre code fonctionne comme prévu.

PyTest facilite l’écriture et l’exécution de ces tests, et avec ses fonctionnalités puissantes, vous pouvez gérer des besoins de test plus complexes à mesure que vous progressez dans votre parcours Python.

Source:
https://www.tecmint.com/unit-testing-python-code-with-pytest/