Pour quelles raisons tester son code ?
Dans un précédent article, nous avons vu pourquoi les tests unitaires sont fondamentaux pour assurer la qualité et le bon fonctionnement d’un code.
Pour rappel, les tests unitaires permettent de tester isolément différentes parties d’un code contrairement aux tests d’intégration qui vérifient le fonctionnement du code dans son ensemble. Ils se différencient également des tests fonctionnels (functional testing) qui permettent de s’assurer du fonctionnement d’une fonctionnalité spécifique.
Pourquoi utiliser le framework Pytest pour tester son code ?
Afin de faciliter l’automatisation des tests unitaires, il est possible d’utiliser des frameworks de test ou « testing frameworks » qui permettent de normaliser leur écriture, d’identifier rapidement les tests qui échouent et de faciliter leur maintenance .
Sur Python, il existe différents frameworks de tests dont les plus connus sont Unittest et Pytest. Aujourd’hui, nous nous concentrerons sur l’implémentation de tests unitaires avec Pytest dont la prise en main est un peu plus simple.
Comment utiliser Pytest ?
Tout d’abord, il vous faudra installer la librairie Pytest avec la commande pip install pytest.
Dans un dossier, nous créons un fichier student.py. À l’intérieur nous créons une classe Student qui permet de créer des instance d’étudiants, d’enregistrer leurs notes et de calculer leur moyenne.
Dans le même dossier, nous créons un fichier de test student_test.py. Le nom des fichiers de test doivent s’écrire sous le format « test_nom_du_fichier.py » ou « nom_du_fichier_test.py ». Dans le fichier, chaque test devra être défini par une fonction préfixée par « test ».
Les assert statements permettent de vérifier que la fonction renvoie un résultat correct pour des arguments donnés et de lever une exception si la condition est fausse. Dans notre exemple, les deux premières fonctions vérifient les propriétés (grades, academic average) d’un objet de type Student lors de son instanciation puis la valeur de la moyenne après ajout d’une note de 12.
Si les fichiers de tests sont correctement préfixés, il suffira de lancer la commande python -m pytest dans votre terminal pour les lancer. Pour lancer un test en particulier, exécutez la commande python -m pytest nom_du_fichier.py.
Après exécution, Pytest fournit un rapport détaillé des tests.
Les « collected items » correspondent au nombre de tests qui sont exécutés. Ici, nos 3 tests sont passés.
Nous modifions temporairement notre fichier student.py pour qu’à l’instanciation d’un étudiant, il ait par défaut eu une note de 10.
Dans notre fichier student_test.py, nous masquons les 2 premières fonctions de test pour conserver uniquement la fonction de test_add_grades, puis nous exécutons le fichier de test.
Nous constatons que le test ne passe plus car les modifications effectuées dans notre fichier student.py rendent l’assertion fausse. Pytest nous permet ainsi de voir si les modifications d’un code impactent ou non le résultat attendu.
NB : pour la suite, il sera nécessaire de modifier la fonction init de student.py pour revenir à une liste vide lors de l’instanciation.
Éviter la répétition avec les pytest fixtures
Dans l’exemple précédent, nous avons instancié un objet de type Student dans chaque test. Pour éviter de réécrire un code utilisé dans plusieurs tests, Pytest dispose d’un décorateur spécifique appelé fixture qui permet d’accéder facilement aux éléments nécessaires à l’exécution d’un test, de la donnée par exemple. Pour spécifier qu’une fonction est une fixture, il sera nécessaire d’utiliser le décorateur @pytest.fixture avant de la définir. Il faudra également passer la fixture en argument des fonctions de tests où vous souhaitez l’appeler.
Dans cet exemple, la fixture nous évite de ré-instancier l’objet étudiant dans chaque test.
Le décorateur parametrize tests pour tester une suite d’instructions
La paramétrisation permet d’exécuter le même test avec différentes valeurs. Pour cela nous utilisons le décorateur @pytest.mark.parametrize. Il faudra préciser le nom des arguments à tester ainsi que leur valeur.
Conclusion
Dans cet article, nous nous sommes initiés à l’utilisation de Pytest pour tester un code. En tant que Data Engineer ou Data Scientist, la mise en place de tests unitaires est une étape nécessaire pour garantir la qualité d’un code et réduire les problèmes lors du déploiement. Il faut néanmoins rappeler que cette étape n’est pas suffisante. D’une part, lors du développement d’une application de Machine Learning, certains éléments peuvent passer entre les mailles du filet. De plus, les tests unitaires ne peuvent, par définition, tester l’interaction entre les unités.
Pour découvrir le métier de Data Engineer et le parcours de formation que nous proposons, n’hésitez pas à consulter notre page dédiée.