.. _td1aunittestcirst: ========================================================= 1A.soft - Tests unitaires, setup et ingéniérie logicielle ========================================================= .. only:: html **Links:** :download:`notebook `, :downloadlink:`html `, :download:`python `, :downloadlink:`slides `, :githublink:`GitHub|_doc/notebooks/td1a_soft/td1a_unit_test_ci.ipynb|*` On vérifie toujours qu’un code fonctionne quand on l’écrit mais cela ne veut pas dire qu’il continuera à fonctionner à l’avenir. La robustesse d’un code vient de tout ce qu’on fait autour pour s’assurer qu’il continue d’exécuter correctement. .. code:: ipython3 from jyquickhelper import add_notebook_menu add_notebook_menu() .. contents:: :local: .. code:: ipython3 from pyensae.graphhelper import draw_diagram Petite histoire --------------- Supposons que vous ayez implémenté trois fonctions qui dépendent les unes des autres. la fonction ``f3`` utilise les fonctions ``f1`` et ``f2``. .. code:: ipython3 draw_diagram("blockdiag { f0 -> f1 -> f3; f2 -> f3;}") .. image:: td1a_unit_test_ci_4_0.png Six mois plus tard, vous créez une fonction ``f5`` qui appelle une fonction ``f4`` et la fonction ``f2``. .. code:: ipython3 draw_diagram('blockdiag { f0 -> f1 -> f3; f2 -> f3; f2 -> f5 [color="red"]; f4 -> f5 [color="red"]; }') .. image:: td1a_unit_test_ci_6_0.png Ah au fait, ce faisant, vous modifiez la fonction ``f2`` et vous avez un peu oublié ce que faisait la fonction ``f3``\ … Bref, vous ne savez pas si la fonction ``f3`` sera impactée par la modification introduite dans la fonction ``f2`` ? C’est ce type de problème qu’on rencontre tous les jours quand on écrit un logiciel à plusieurs et sur une longue durée. Ce notebook présente les briques classiques pour s’assurer de la robustesse d’un logiciel. - les tests unitaires - un logiciel de suivi de source - calcul de couverture - l’intégration continue - écrire un setup - écrire la documentation - publier sur `PyPi `__ Ecrire une fonction ------------------- N’importe quel fonction qui fait un calcul, par exemple une fonction qui résoud une équation du second degré. .. code:: ipython3 def solve_polynom(a, b, c): # .... return None Ecrire un test unitaire ----------------------- Un `test unitaire `__ est une fonction qui s’assure qu’une autre fonction retourne bien le résultat souhaité. Le plus simple est d’utiliser le module standard `unittest `__ et de quitter les notebooks pour utiliser des fichiers. Parmi les autres alternatives : `pytest `__ et `nose `__. Couverture ou coverage ---------------------- La `couverture de code `__ est l’ensemble des lignes exécutées par les tests unitaires. Cela ne signifie pas toujours qu’elles soient correctes mais seulement qu’elles ont été exécutées une ou plusieurs sans provoquer d’erreur. Le module le plus simple est `coverage `__. Il produit des rapports de ce type : `mlstatpy/coverage `__. Créer un compte GitHub ---------------------- `GitHub `__ est un site qui contient la majorité des codes des projets open-source. Il faut créer un compte si vous n’en avez pas, c’est gratuit pour les projets open souce, puis créer un projet et enfin y insérer votre projet. Votre ordinateur a besoin de : - `git `__ - `GitHub destkop `__ Vous pouvez lire `GitHub Pour les Nuls : Pas de Panique, Lancez-Vous ! (Première Partie) `__ et bien sûr faire plein de recherches internet. **Note** Tout ce que vous mettez sur GitHub pour un projet open-source est en accès libre. Veillez à ne rien mettre de personnel. Un compte GitHub fait aussi partie des choses qu’un recruteur ira regarder en premier. Intégration continue -------------------- L’\ `intégration continue `__ a pour objectif de réduire le temps entre une modification et sa mise en production. Typiquement, un développeur fait une modification, une machine exécute tous les tests unitaires. On en déduit que le logiciel fonctionne sous tous les angles, on peut sans crainte le mettre à disposition des utilisateurs. Si je résume, l’intégration continue consiste à lancer une batterie de tests dès qu’une modification est détectée. Si tout fonctionne, le logiciel est construit et prêt à être partagé ou déployé si c’est un site web. Là encore pour des projets open-source, il est possible de trouver des sites qui offre ce service gratuitement : - `travis `__ - `Linux `__ - `appveyor `__ - `Windows `__ - 1 job à la fois, pas plus d’une heure. - `circle-ci `__ - `Linux `__ et `Mac OSX `__ (payant) - `GitLab-ci `__ A part `GitLab-ci `__, ces trois services font tourner les tests unitaires sur des machines hébergés par chacun des sociétés. Il faut s’enregistrer sur le site, définir un fichier `.travis.yml `__, `.appveyor.yml `__ ou `circle.yml `__ puis activer le projet sur le site correspondant. Quelques exemples sont disponibles à `pyquickhelper `__ ou `scikit-learn `__. Le fichier doit être ajouté au projet sur *GitHub* et activé sur le site d’intégration continue choisi. La moindre modification déclenchera un nouveau *build*.permet La plupart des sites permettent l’insertion de `badge `__ de façon à signifier que le *build* fonctionne. .. code:: ipython3 from IPython.display import Image try: im = Image("https://travis-ci.com/sdpython/ensae_teaching_cs.png") except TimeoutError: im = None im .. image:: td1a_unit_test_ci_17_0.png .. code:: ipython3 from IPython.display import SVG try: im = SVG("https://codecov.io/github/sdpython/ensae_teaching_cs/coverage.svg") except TimeoutError: im = None im .. image:: td1a_unit_test_ci_18_0.svg Il y a des badges un peu pour tout. Ecrire un setup --------------- Le fichier ``setup.py`` détermin la façon dont le module python doit être installé pour un utilisateur qui ne l’a pas développé. Comment construire un setup : `setup `__. Ecrire la documentation ----------------------- L’outil est le plus utilisé est `sphinx `__. Saurez-vous l’utiliser ? Dernière étape : PyPi --------------------- `PyPi `__ est un serveur qui permet de mettre un module à la disposition de tout le monde. Il suffit d’uploader le module… `Packaging and Distributing Projects `__ ou `How to submit a package to PyPI `__. PyPi permet aussi l’insertion de badge. .. code:: ipython3 try: im = SVG("https://badge.fury.io/py/ensae_teaching_cs.svg") except TimeoutError: im = None im .. image:: td1a_unit_test_ci_25_0.svg