2022-11-12 22:58 Temps de lecture : 14 min

Tests unitaires avec le module Python unittest

Tout développeur consciencieux sait qu'il est impensable de déployer du code sans une batterie de tests rigoureux. Le test unitaire se concentre précisément sur l'évaluation des composants individuels d'un programme complexe.

Cet article a pour objectif de vous guider à travers le processus de mise en œuvre de tests unitaires pour votre code Python, en utilisant le module 'unittest'. Avant de plonger dans les détails, il est essentiel de comprendre les différentes catégories de tests.

De manière générale, on distingue les tests manuels et les tests automatisés. Les tests manuels sont réalisés par des personnes qui exécutent des scénarios de test après la fin du développement. Les tests automatisés, quant à eux, s'appuient sur des programmes qui effectuent les tests et produisent les résultats.

Il est clair que les tests manuels sont souvent chronophages et difficiles à mettre en œuvre. C'est pourquoi les développeurs privilégient l'écriture de code pour effectuer des tests de manière automatisée. Il existe plusieurs types de tests automatisés, notamment les tests unitaires, les tests d'intégration, les tests de bout en bout, les tests de charge, etc.

Voici le déroulement classique d'un processus de test:

  • Écriture ou modification du code source.
  • Élaboration ou mise à jour de tests pour couvrir différents scénarios d'utilisation.
  • Exécution des tests (manuellement ou via un outil de test).
  • Analyse des résultats des tests. En cas d'erreur, correction du code et itération du processus.

Nous allons nous concentrer sur le test unitaire, qui est la forme de test la plus fondamentale et cruciale. Sans plus attendre, entrons dans le vif du sujet de ce tutoriel.

Qu'est-ce qu'un test unitaire ?

Le test unitaire consiste à tester un petit bloc de code indépendant. Dans la plupart des cas, ce bloc de code est une fonction. Le terme "indépendant" signifie que le code testé ne dépend d'aucun autre code du projet.

Prenons un exemple : imaginons que nous voulions vérifier si une chaîne de caractères est égale à « toptips.fr ». Pour cela, nous créons une fonction qui prend une chaîne en argument et retourne si elle est égale ou non à « toptips.fr ».

def is_equal_to_geekflare(string):
  return string == "toptips.fr"

Cette fonction est autonome ; elle ne dépend pas d'autres portions de code. On peut donc la tester indépendamment en lui fournissant diverses entrées. Ce type de code indépendant est souvent réutilisé dans l'ensemble d'un projet.

L'importance des tests unitaires

Les blocs de code indépendants sont souvent réutilisés dans un projet. Il est donc crucial qu'ils soient bien écrits et testés. C'est précisément le rôle des tests unitaires. Mais que se passe-t-il si l'on néglige les tests unitaires ?

Si l'on ne teste pas les petits blocs de code individuels, les tests d'intégration, les tests de bout en bout et autres tests qui dépendent de ces blocs peuvent échouer. Ceci peut causer des dysfonctionnements majeurs de l'application. Il est donc essentiel de tester minutieusement les fondations du code.

Maintenant que nous avons souligné l'importance des tests unitaires, nous comprenons la nécessité de les écrire pour chaque bloc de code indépendant. Si les tests unitaires sont bien effectués, les autres tests ne risquent pas d'échouer à cause de ces blocs de code.

Dans les sections qui suivent, nous allons explorer le module 'unittest' de Python et découvrir comment l'utiliser pour écrire des tests unitaires.

Note : Il est supposé que vous connaissez les bases de Python comme les classes et les modules. Si vous n'êtes pas familier avec ces concepts, vous risquez de rencontrer des difficultés pour comprendre les parties suivantes.

Qu'est-ce que le module unittest de Python ?

Le module 'unittest' de Python est un framework de test intégré qui permet de tester du code Python. Il offre un lanceur de test qui simplifie l'exécution des tests. Ce module intégré est suffisant pour commencer à tester en Python, mais vos besoins spécifiques peuvent justifier l'utilisation de modules tiers. 'unittest' est un excellent point de départ pour l'introduction aux tests en Python.

Voici les étapes à suivre pour tester du code Python avec le module 'unittest' :

#1. Écrire le code.

#2. Importer le module 'unittest'.

#3. Créer un fichier dont le nom commence par le mot-clé 'test'. Par exemple, 'test_prime.py'. Ce mot-clé permet d'identifier les fichiers de test.

#4. Créer une classe qui hérite de la classe 'unittest.TestCase'.

#5. Définir des méthodes (tests) à l'intérieur de cette classe. Chaque méthode doit contenir un ou plusieurs cas de test. Le nom de la méthode doit commencer par le mot-clé 'test'.

#6. Exécuter les tests. Il existe différentes manières de procéder :

  • Utiliser la commande 'python -m unittest nom_du_fichier_de_test.py'.
  • Exécuter le fichier de test comme un script Python standard avec la commande 'python nom_du_fichier_de_test.py'. Pour que cette méthode fonctionne, il faut appeler la méthode 'unittest.main()' dans le fichier de test.
  • Utiliser la découverte de test. La commande 'python -m unittest discover' permet d'exécuter automatiquement tous les tests, sans spécifier explicitement le nom des fichiers, en se basant sur la convention de nommage adoptée.

En général, lors des tests, on compare la sortie réelle du code avec la sortie attendue. Pour faciliter ces comparaisons, 'unittest' propose différentes méthodes. Vous pouvez trouver la liste complète des fonctions d'assertion ici.

Ces méthodes sont simples à utiliser et à comprendre.

Assez de théorie, passons à la pratique !

Note : Si vous avez des questions sur le module 'unittest', consultez la documentation. Sans plus tarder, mettons en pratique le module 'unittest'.

Tests unitaires en Python avec 'unittest'

Commençons par créer quelques fonctions. Ensuite, nous nous concentrerons sur l'écriture des tests. Ouvrez un dossier dans votre éditeur de code préféré et créez un fichier nommé 'utils.py'. Copiez le code suivant dans ce fichier:

import math


def is_prime(n):
    if n < 0:
        return 'Les nombres négatifs ne sont pas autorisés'

    if n <= 1:
        return False

    if n == 2:
        return True

    if n % 2 == 0:
        return False

    for i in range(2, int(math.sqrt(n)) + 1):
        if n % i == 0:
            return False
    return True


def cubic(a):
    return a * a * a


def say_hello(name):
    return "Bonjour, " + name

Nous avons trois fonctions dans le fichier 'utils.py'. Il est temps de tester chacune de ces fonctions avec différents cas de test. Commençons par la fonction 'is_prime'.

#1. Créez un fichier nommé 'test_utils.py' dans le même dossier que 'utils.py'.

#2. Importez les modules 'utils' et 'unittest'.

#3. Créez une classe nommée 'TestUtils' qui hérite de la classe 'unittest.TestCase'. Le nom de la classe est arbitraire, mais essayez de choisir un nom significatif.

#4. À l'intérieur de cette classe, définissez une méthode nommée 'test_is_prime' qui prend l'argument 'self'.

#5. Écrivez différents cas de test en appelant la fonction 'is_prime' avec diverses entrées et en comparant les sorties avec les résultats attendus.

#6. Exemple de cas de test : 'self.assertFalse(utils.is_prime(1))'.

#7. Dans ce cas, nous nous attendons à ce que la fonction 'is_prime(1)' retourne 'False'.

#8. De même, nous allons écrire d'autres cas de test en fonction de la logique de la fonction.

Voici les tests :

import unittest

import utils


class TestUtils(unittest.TestCase):
    def test_is_prime(self):
        self.assertFalse(utils.is_prime(4))
        self.assertTrue(utils.is_prime(2))
        self.assertTrue(utils.is_prime(3))
        self.assertFalse(utils.is_prime(8))
        self.assertFalse(utils.is_prime(10))
        self.assertTrue(utils.is_prime(7))
        self.assertEqual(utils.is_prime(-3),
                         "Les nombres négatifs ne sont pas autorisés")


if __name__ == '__main__':
    unittest.main()

Nous appelons la méthode 'unittest.main()' pour exécuter les tests à l'aide de la commande 'python filename.py'. Exécutez les tests.

Vous devriez voir une sortie similaire à celle-ci :

$ python test_utils.py 
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

Maintenant, essayez d'écrire les cas de test pour les autres fonctions. Réfléchissez à différents scénarios d'utilisation et testez les fonctions en conséquence. Voici les tests ajoutés à la classe :

...


class TestUtils(unittest.TestCase):
    def test_is_prime(self):
        ...

    def test_cubic(self):
        self.assertEqual(utils.cubic(2), 8)
        self.assertEqual(utils.cubic(-2), -8)
        self.assertNotEqual(utils.cubic(2), 4)
        self.assertNotEqual(utils.cubic(-3), 27)

    def test_say_hello(self):
        self.assertEqual(utils.say_hello("toptips.fr"), "Bonjour, toptips.fr")
        self.assertEqual(utils.say_hello("Chandan"), "Bonjour, Chandan")
        self.assertNotEqual(utils.say_hello("Chandan"), "Salut, Chandan")
        self.assertNotEqual(utils.say_hello("Hafeez"), "Salut, Hafeez")


...

Nous avons utilisé certaines des fonctions de comparaison du module 'unittest'. La liste complète est disponible ici.

Vous savez maintenant comment écrire des tests unitaires avec le module 'unittest'. Il est temps d'explorer différentes façons d'exécuter les tests.

Comment exécuter les tests avec 'unittest'

Nous avons déjà vu une méthode pour exécuter les cas de test. Découvrons les deux autres méthodes :

#1. Utilisation du nom de fichier et du module 'unittest'.

Dans cette méthode, nous utilisons le module 'unittest' et le nom de fichier pour exécuter les tests. La commande est 'python -m unittest nom_du_fichier.py'. Dans notre cas, la commande est 'python -m unittest test_utils.py'.

#2. Utilisation de la découverte de test

Nous allons utiliser la fonction de découverte du module 'unittest' pour détecter automatiquement tous les fichiers de test et les exécuter. Pour cela, les fichiers de test doivent être nommés en commençant par le mot-clé 'test'.

La commande pour exécuter les tests avec la découverte est 'python -m unittest discover'. Cette commande va détecter tous les fichiers dont le nom commence par 'test' et les exécuter.

Conclusion 👩‍💻

Les tests unitaires sont les tests de base dans le monde de la programmation. Il existe de nombreux autres types de tests. Apprenez-les progressivement. J'espère que ce tutoriel vous aidera à écrire vos premiers tests unitaires en Python avec le module 'unittest'. Sachez qu'il existe des bibliothèques tierces comme pytest, Robot Framework, nose, nose2, slash, etc. Vous pouvez les explorer en fonction des besoins de vos projets.

Bon test 😎

Vous pourriez aussi être intéressé par Questions et réponses d'entretiens Python.

Auteur
France

Rédacteur tech, guides pratiques et astuces numériques.