Les tests sur le parcours Python

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.

Installe pytest

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.

Windows

PS C:\Users\foobar> py -m pip install pytest pytest-cache pytest-subtests pytest-pylint
Successfully installed pytest-8.3.3 ...

Linux / MacOS

$ 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

Lance les tests

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>

Note

<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 ====================

Corrige les avertissements

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

Échecs des tests

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 ==========

Arguments supplémentaires

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.

Renvoie tous les détails [-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

.......

Arrête après le premier échec [-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 ==========

Tests échoués en premier [--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 ====================

Workflow recommandé

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.

Utilise PDB, le débogueur Python, avec pytest

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.

Étends ton IDE

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.

Informations complémentaires

Ajoute python à ton PATH

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>.

Windows

Clique sur le bouton Windows Start, recherche Edit the system environment variables et appuie sur Entrée. Ensuite, appuie sur Environment Variables... :

Appuie sur le bouton bleu, lol

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

Sélection de la variable path

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

Ajoute python au path

MacOS/Linux

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>"