Apprends à tester tes exercices Python sur Exercism.
On utilise pytest comme exécuteur de tests sur le site.
Tu devras installer pytest sur ta machine de développement si tu veux télécharger et exécuter en local les tests des exercices du parcours Python.
Tu devrais aussi installer les plugins pytest suivants :
On te recommande aussi d'utiliser le programme de linting pylint, car il fait partie de notre retour automatisé sur le site et peut être un outil d'analyse statique de code très utile.
Pour plus de simplicité, le plugin pytest-pylint pour pytest te permet d'exécuter pylint via pytest en ligne de commande.
La configuration de Pylint peut être un peu lourde, donc ce tutoriel de pylint.readthedocs.io peut t'aider à démarrer, tout comme cet aperçu de Code Quality: Tools and Best Practices de Real Python.
Pytest peut être installé et mis à jour à l'aide de l'utilitaire Python intégré pip.
Pour d'autres astuces, Brett Cannon propose un bon guide express sur la façon d'installer des paquets pour Python, ainsi qu'une excellente explication sur pourquoi tu devrais utiliser python -m pip.
Pour en savoir plus sur les arguments en ligne de commande de Python, voir ligne de commande et environnement dans la documentation Python.
Note : Python3 et py peuvent être ou non des alias de Python sur ton système.
Adapte les commandes d'installation ci-dessous en conséquence.
Pour installer pytest dans un environnement virtuel, assure-toi que l'environnement est activé avant d'exécuter des commandes.
Sinon, l'installation de pytest sera globale.
PS C:\Users\foobar> py -m pip install pytest pytest-cache pytest-subtests pytest-pylint
Successfully installed pytest-8.3.3 ...
$ python3 -m pip install pytest pytest-cache pytest-subtests pytest-pylint
Successfully installed pytest-8.3.3 ...
Pour vérifier que l'installation a réussi :
$ python3 -m pytest --version
pytest 8.3.3
Pour lancer les tests, place-toi dans le dossier où se trouve l'exercice à l'aide de cd dans ton terminal (remplace <exercise-folder-location> ci-dessous par ton chemin).
$ cd <exercise-folder-location>
<exercise-folder-location>, ou la plupart des éléments entre chevrons, désignent une valeur à remplacer.
Un chemin ou un nom de fichier normal doit s'écrire sans aucun crochet.
Par exemple : /Users/janedoe/exercism/python/exercises/concept/chaitanas-colossal-coaster (sur les systèmes *nix), C:\Users\janedoe\exercism\python\exercises\practice\hello-world\ (sous Windows), myFolder ou my_file.py.
Le fichier que tu voudras lancer se termine généralement par _test.py.
Ce fichier contient les tests pour la solution de l'exercice, et ce sont les mêmes tests que ceux exécutés sur le site lorsqu'une solution est envoyée.
Ensuite, exécute la commande suivante dans ton terminal, en remplaçant <exercise_test.py> par l'emplacement ou le nom du fichier de test :
$ python3 -m pytest -o markers=task <exercise_test.py>
==================== 7 passed in 0.08s ====================
Si tu n'utilises pas pytest -o markers=task dans la commande ci-dessus, il est possible que tu obtiennes des warnings à propos de « unknown markers » lorsque tu lances un test qui utilise notre nouvelle syntaxe.
Pour éviter de taper pytest -o markers=task à chaque test que tu lances, tu peux utiliser un fichier de configuration pytest.ini, que tu peux télécharger à la racine du répertoire du parcours Python : pytest.ini.
Tu peux aussi créer ton propre fichier pytest.ini avec le contenu suivant :
[pytest]
markers =
task: A concept exercise task.
Placer ce fichier dans le répertoire racine ou de travail des exercices Exercism enregistrera les marques et fera disparaître les avertissements.
Tu trouveras plus d'informations sur les marques pytest dans la documentation de pytest sur le marquage des fonctions de test et dans la documentation de pytest sur l'utilisation de marqueurs personnalisés.
Tu trouveras plus d'informations sur la personnalisation des configurations pytest dans la documentation de pytest sur les formats de fichiers de configuration
Lorsque des tests échouent, pytest affiche dans le terminal le texte de chaque test en échec, ainsi que les valeurs return attendues et réelles de chacun.
Voici un exemple générique d'un test en échec :
$(my_venv) python3 -m pytest -o markers=task <exercise_test.py>
=================== FAILURES ====================
______________ name_of_failed_test ______________
# Test code inside of <exercise_test.py> that failed.
...
E TypeOfError: ReturnedValue != ExpectedValue
exercise_test.py:<line_of_failed_test>: TypeOfError
============ short test summary info ============
FAILED exercise_test.py::ExerciseTest::name_of_failed_test
========== 1 failed, 2 passed in 0.13s ==========
Si tu veux vraiment contrôler précisément ce que pytest affiche à l'écran, voici quelques arguments de ligne de commande pratiques qui te permettent de configurer son comportement.
-v]Ajouter l'option -v (verbose) affichera les informations sur l'environnement et un résumé des tests, en plus des tests en échec :
$(my_venv) python3 -m pytest -o markers=task -v exercises/<exercise_name>/<test_file_test.py>
======================================== test session starts ===========================================
platform darwin -- Python 3.9.0, pytest-6.2.5, -- /usr/local/envs/my_env/bin/python3
cachedir: .pytest_cache
metadata: {'Python': '3.9.0', 'Platform': 'macOS-10.14.6-x86_64-i386-64bit', 'Packages': {'pytest': '6.2.1'}, 'Plugins': {'subtests': '0.5.0', 'pylint': '0.18.0'}
rootdir: /Users/<user>/exercism/python, configfile: pytest.ini
plugins: subtests-0.5.0, pylint-0.18.0
collected 5 items
exercises/exercise-name/exercise_file_test.py::ExerciseNameTest::test_one FAILED [ 20%]
exercises/exercise-name/exercise_file_test.py::ExerciseNameTest::test_two FAILED
exercises/exercise-name/exercise_file_test.py::ExerciseNameTest::test_three PASSED [ 40%]
exercises/concept/exercise-name/exercise_file_test.py::ExerciseNameTest::test_four FAILED
exercises/concept/exercise-name/exercise_file_test.py::ExerciseNameTest::test_five PASSED [ 60%]
exercises/concept/exercise-name/exercise_file_test.py::ExerciseNameTest::test_six FAILED
exercises/concept/exercise-name/exercise_file_test.py::ExerciseNameTest::test_seven PASSED [ 80%]
exercises/concept/exercise-name/exercise_file_test.py::ExerciseNameTest::test_eight FAILED
exercises/concept/exercise-name/exercise_file_test.py::ExerciseNameTest::test_nine PASSED [100%]
================================================ FAILURES ======================================================
# Failed tests are then individually printed out below
.......
-x]Utiliser l'option -x lance les tests normalement, mais arrête l'exécution dès le premier test en échec.
C'est utile lorsque tu veux déboguer une seule tâche ou un seul échec de test à la fois :
$(my_venv) python3 -m pytest -o markers=task -x exercises/<exercise_name>/<test_file_test.py>
=================== FAILURES ====================
_______________ example_test_foo ________________
...
...
============ short test summary info ============
FAILED example_test.py::ExampleTest::example_test_foo
!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!
========== 1 failed, 5 passed in 0.28s ==========
--ff]Le plugin pytest-cache se souvient des tests qui ont échoué lors de ta dernière exécution de pytest, donc utiliser l'option --ff demande à pytest d'exécuter en premier les tests qui ont échoué auparavant, puis de poursuivre avec le reste des tests.
Cela peut accélérer tes tests si tu apportes de nombreuses petites corrections autour d'une tâche ou d'un ensemble d'entrées particuliers.
$(my_venv) python3 -m pytest -o markers=task --ff <example_file_test.py>
==================== 7 passed in 503s ====================
On te recommande d'utiliser les commandes suivantes pour rendre ton débogage plus facile et (peut-être) plus rapide.
Commence par changer ton répertoire de travail pour celui de l'exercice que tu veux tester :
$(my_venv) cd path/to/exercise
Ensuite, lance les tests avec les arguments expliqués plus haut -x et --ff :
$(my_venv) python3 -m pytest -o markers=task -x --ff <example_file_test.py>
Cela testera ta solution.
Lorsque pytest rencontre un test en échec, le programme s'arrête et t'indique quel test a échoué.
Lorsque tu apportes des corrections et relances les tests, pytest exécute d'abord le test qui a échoué auparavant, puis poursuit avec les autres tests.
Si tu veux « déboguer comme un pro », tu peux utiliser l'argument --pdb après la commande pytest, et passer dans le débogueur Python intégré, PDB.
$(my_venv) python3 -m pytest -o markers=task -x --ff --pdb <example_file_test.py>
=============== 4 passed in 0.15s ===============
Lorsqu'un test échoue, passer dans PDB te permet de parcourir ton code pas à pas en visualisant la portée actuelle, ainsi que de vérifier la valeur des variables et la signature des différentes fonctions.
Tu trouveras plus de détails sur le module PDB dans la documentation Python sur PDB.
En outre, la documentation pytest sur PDB et ce guide de Real Python sont extrêmement utiles.
Si tu souhaites étendre ton IDE avec des outils qui t'aideront à tester et à améliorer ton code, consulte la page outils. On y explore plusieurs IDE, éditeurs et quelques extensions utiles pour le linting et le débogage.
Note : Si tu as installé Python sous Windows via le programme d'installation de la PSF, la commande sera py et non python3.
Taper python3 -m à chaque fois que tu veux exécuter un module peut devenir un peu pénible.
Pour éviter cela, tu peux ajouter le dossier Scripts de ton installation Python à ton path.
Si tu ne sais pas où tu as installé Python, exécute la commande suivante dans ton terminal :
$ python3 -c "import os, sys; print(os.path.dirname(sys.executable))"
<python_directory>
Le répertoire renvoyé est celui où ta version active actuelle de Python est installée ; dans cette section, il est appelé <python_directory>.
Clique sur le bouton Windows Start, recherche Edit the system environment variables et appuie sur Entrée.
Ensuite, appuie sur Environment Variables... :

Trouve ensuite la variable Path dans tes User variables, sélectionne-la et clique sur Edit... :

Ajoute ensuite une nouvelle ligne, comme le montre l'image, en remplaçant <python_directory> par le répertoire d'installation de Python :

Ce qui suit devrait fonctionner pour la plupart des variantes de Linux et de MacOS avec un shell bash.
Les commandes peuvent varier selon la distribution Linux et selon que tu utilises un shell fish ou zsh.
Remplace <python_directory> par la sortie de python3 -c "import os, sys; print(os.path.dirname(sys.executable))"
export PATH="$PATH:<python_directory>"