Scopri come testare i tuoi esercizi Python su Exercism.
Usiamo pytest per eseguire i test sul sito.
Se vuoi scaricare ed eseguire in locale i test degli esercizi del track Python, dovrai installare pytest sulla tua macchina di sviluppo.
Dovresti anche installare i seguenti plugin di pytest:
Consigliamo anche di usare il programma di linting del codice pylint, perché fa parte del feedback automatico sul sito e può essere uno strumento di analisi statica del codice molto utile.
Per semplificarti la vita, il plugin pytest-pylint per pytest ti permette di eseguire pylint tramite pytest dalla riga di comando.
Configurare Pylint può essere un po' complicato, quindi questo tutorial di pylint.readthedocs.io può esserti utile per iniziare, così come questa panoramica di Code Quality: Tools and Best Practices di Real Python.
Pytest si può installare e aggiornare usando l'utilità integrata di Python pip.
Per altri consigli, Brett Cannon ha scritto una bella guida rapida e spicciola su come installare i pacchetti per Python, insieme a un'ottima spiegazione del perché dovresti usare python -m pip.
Per saperne di più sugli argomenti della riga di comando di Python, vedi riga di comando e ambiente nella documentazione di Python.
Nota: Python3 e py possono essere o non essere alias di Python sul tuo sistema.
Adatta di conseguenza i comandi di installazione qui sotto.
Per installare pytest in un ambiente virtuale, assicurati che l'ambiente sia attivato prima di eseguire i comandi.
Altrimenti, l'installazione di pytest sarà 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 ...
Per verificare che l'installazione sia andata a buon fine:
$ python3 -m pytest --version
pytest 8.3.3
Per eseguire i test, vai nella cartella in cui è salvato l'esercizio usando cd nel terminale (sostituisci <exercise-folder-location> qui sotto con il tuo percorso).
$ cd <exercise-folder-location>
<exercise-folder-location>, o quasi tutto ciò che sta tra parentesi angolari, indica un valore segnaposto.
Un percorso o un nome di file normale va scritto senza parentesi.
Per esempio: /Users/janedoe/exercism/python/exercises/concept/chaitanas-colossal-coaster (sui sistemi *nix), C:\Users\janedoe\exercism\python\exercises\practice\hello-world\ (su Windows), myFolder o my_file.py.
Il file che vorrai eseguire di solito termina con _test.py.
Questo file contiene i test per la soluzione dell'esercizio, e sono gli stessi test che vengono eseguiti sul sito quando si carica una soluzione.
Poi esegui il comando seguente nel terminale, sostituendo <exercise_test.py> con il percorso o il nome del file di test:
$ python3 -m pytest -o markers=task <exercise_test.py>
==================== 7 passed in 0.08s ====================
Se non usi pytest -o markers=task nel comando qui sopra, è possibile che tu riceva degli warnings su «unknown markers» quando esegui un test che usa la nostra nuova sintassi.
Per evitare di digitare pytest -o markers=task per ogni test che esegui, puoi usare un file di configurazione pytest.ini, che puoi scaricare dalla cartella principale del track Python: pytest.ini.
Puoi anche creare un tuo file pytest.ini con il contenuto seguente:
[pytest]
markers =
task: A concept exercise task.
Se metti questo file nella cartella root o working degli esercizi di Exercism, i marcatori verranno registrati e gli avvisi spariranno.
Maggiori informazioni sui marcatori di pytest si trovano nella documentazione di pytest su contrassegnare le funzioni di test e nella documentazione di pytest su lavorare con marcatori personalizzati.
Maggiori informazioni sulla personalizzazione della configurazione di pytest si trovano nella documentazione di pytest su formati dei file di configurazione
Quando i test falliscono, pytest stampa nel terminale il testo di ogni test fallito, insieme ai valori return attesi ed effettivi di ciascuno.
Qui sotto c'è un esempio generico di test fallito:
$(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 ==========
Se vuoi davvero controllare con precisione cosa pytest restituisce sullo schermo, ecco alcuni comodi argomenti della riga di comando che ti permettono di configurarne il comportamento.
-v]Aggiungendo il flag -v (verbose), oltre ai test falliti otterrai anche le informazioni sull'ambiente e un riepilogo dei test:
$(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]Usando il flag -x, i test vengono eseguiti normalmente, ma l'esecuzione si ferma al primo test fallito.
È utile quando vuoi fare il debug di un singolo task o di un singolo test fallito alla volta:
$(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]Il plugin pytest-cache ricorda quali test sono falliti l'ultima volta che hai eseguito pytest, quindi usando il flag --ff dirai a pytest di eseguire prima i test falliti in precedenza, per poi proseguire con tutti gli altri.
Può velocizzare l'esecuzione dei test se stai facendo molte piccole correzioni su un particolare task o insieme di input.
$(my_venv) python3 -m pytest -o markers=task --ff <example_file_test.py>
==================== 7 passed in 503s ====================
Ti consigliamo di usare i comandi seguenti per rendere il debug più semplice e (forse) più veloce:
Per prima cosa, spostati nella cartella dell'esercizio che vuoi testare:
$(my_venv) cd path/to/exercise
Poi esegui i test insieme agli argomenti -x e --ff spiegati prima:
$(my_venv) python3 -m pytest -o markers=task -x --ff <example_file_test.py>
Così verranno eseguiti i test sulla soluzione.
Quando pytest incontra un test fallito, il programma si ferma e ti dice quale test è fallito.
Quando apporti delle correzioni ed esegui di nuovo i test, pytest eseguirà prima il test che era fallito, poi proseguirà con i test rimanenti.
Se vuoi «fare debug come un professionista», puoi usare l'argomento --pdb dopo il comando pytest e entrare nel debugger di Python integrato, PDB.
$(my_venv) python3 -m pytest -o markers=task -x --ff --pdb <example_file_test.py>
=============== 4 passed in 0.15s ===============
Quando un test fallisce, entrando in PDB potrai eseguire il codice passo dopo passo, osservando lo scope corrente e controllando il valore delle variabili e la firma delle varie funzioni.
Maggiori dettagli sul modulo PDB si trovano nella documentazione di Python su PDB.
Inoltre, la documentazione di pytest su PDB e questa guida di Real Python sono estremamente utili.
Se vuoi estendere il tuo IDE con alcuni strumenti che ti aiutino a testare e migliorare il codice, dai un'occhiata alla pagina strumenti. Lì esploriamo diversi IDE, editor e alcune estensioni utili per il linting e il debug.
Nota: se hai installato Python su Windows tramite il PSF Installer, il comando sarà py invece di python3.
Digitare python3 -m ogni volta che vuoi eseguire un modulo può diventare un po' fastidioso.
Per evitarlo, puoi aggiungere al tuo path la cartella Scripts della tua installazione di Python.
Se non sai dove hai installato Python, esegui il comando seguente nel terminale:
$ python3 -c "import os, sys; print(os.path.dirname(sys.executable))"
<python_directory>
La cartella restituita è quella in cui è installata la versione di Python attualmente attiva; in questa sezione la chiameremo <python_directory>.
Fai clic sul pulsante Windows Start e cerca Edit the system environment variables, quindi premi invio.
Poi premi Environment Variables...:

Poi individua la variabile Path nelle tue User variables, selezionala e fai clic su Edit...:

Poi aggiungi una nuova riga, come mostrato nell'immagine, sostituendo <python_directory> con la cartella della tua installazione di Python:

Quanto segue dovrebbe funzionare per la maggior parte delle versioni di Linux e MacOS con una shell bash.
I comandi possono variare a seconda della distribuzione Linux e dell'uso di una shell fish o zsh.
Sostituisci <python_directory> con l'output di python3 -c "import os, sys; print(os.path.dirname(sys.executable))"
export PATH="$PATH:<python_directory>"