Esercizio
In questo esercizio si userà pytest con parametrizza per testare una funzione. Si aggiornerà quindi una classe di test per usare una fixture anziché un metodo setup() e teardown(). Usare parametrize e lavorare con le fixture consente di essere più flessibili nella creazione o aggiornamento dei test.
Passaggio 1 - Aggiungere un file con test per questo esercizio
Creare un nuovo file di test denominato test_advanced.py e aggiungere il codice seguente:
def str_to_bool(string): if string.lower() in ['yes', 'y', '1']: return True elif string.lower() in ['no', 'n', '0']: return FalseLa funzione
str_to_bool()accetta una stringa come input e a seconda del relativo contenuto restituisce un valoreTrueoFalse.Nello stesso file aggiungere i test per la funzione
str_to_bool(). Usarepytest.mark.parametrize()per testare prima tutti i valori true:import pytest @pytest.mark.parametrize("string", ['Y', 'y', '1', 'YES']) def test_str_to_bool_true(string): assert str_to_bool(string) is TrueAggiungere quindi un altro test con i valori false:
@pytest.mark.parametrize("string", ['N', 'n', '0', 'NO']) def test_str_to_bool_false(string): assert str_to_bool(string) is FalseSono ora disponibili due test che coprono tutti gli input possibili per i valori restituiti
TrueeFalse.
Nota
La presenza di test come codice effettivo nello stesso file non è comune. Per semplicità, tuttavia, negli esempi di questo esercizio sarà presente codice effettivo nello stesso file. Nei progetti Python reali i test sono separati da file e directory dal codice che esegue il test.
Passaggio 2: Eseguire i test ed esaminare il report
Dopo aver aggiunto i test, il passaggio successivo consiste nell'eseguire pytest e nell'esaminare l'output. Usare il flag di dettaglio aumentato (-v) in modo che sia possibile visualizzare tutti i valori di input trattati come test separati.
$ pytest -v test_avanced.py
============================= test session starts ==============================
Python 3.9.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /private
collected 8 items
test_advanced.py::test_str_to_bool_true[Y] PASSED [ 12%]
test_advanced.py::test_str_to_bool_true[y] PASSED [ 25%]
test_advanced.py::test_str_to_bool_true[1] PASSED [ 37%]
test_advanced.py::test_str_to_bool_true[YES] PASSED [ 50%]
test_advanced.py::test_str_to_bool_false[N] PASSED [ 62%]
test_advanced.py::test_str_to_bool_false[n] PASSED [ 75%]
test_advanced.py::test_str_to_bool_false[0] PASSED [ 87%]
test_advanced.py::test_str_to_bool_false[NO] PASSED [100%]
============================== 8 passed in 0.01s ===============================
Anche se sono state scritte solo due funzioni di test, pytest è riuscito a creare otto test in totale grazie alla funzione parametrize().
Passaggio 3 - Convertire un test esistente in una fixture
Aggiungere un nuovo test basato su classe al file test_advanced.py . Questo test deve usare una funzione
setup()eteardown()che crea un file temporaneo con testo sul file stesso. Dopo ogni test, il file viene rimosso. Avrà un aspetto simile al seguente:import os class TestFile: def setup(self): with open("/tmp/done", 'w') as _f: _f.write("1") def teardown(self): try: os.remove("/tmp/done") except OSError: pass def test_done_file(self): with open("/tmp/done") as _f: contents = _f.read() assert contents == "1"Questa classe di test crea un file, ma è problematica perché il percorso /tmp/ non è garantito che sia presente in ogni sistema.
Creare una fixture che usa la fixture
pytesttmpdir()per scrivere nel file e restituire il percorso:import pytest @pytest.fixture def tmpfile(tmpdir): def write(): file = tmpdir.join("done") file.write("1") return file.strpath return writeLa fixture
tmpfile()usa la fixturetmpdir()di Pytest, che garantisce un file temporaneo valido pulito dopo l'esecuzione dei test.Aggiornare la
TestFileclasse in modo che anziché i metodi di supporto usi la fixture .class TestFile: def test_f(self, tmpfile): path = tmpfile() with open(path) as _f: contents = _f.read() assert contents == "1"Questa classe di test può ora garantire che un file temporaneo venga creato e abbia il contenuto appropriato per il funzionamento dell'asserzione.
Eseguire il test di quanto fatto finora
A questo ora dovrebbe essere presente un file Python denominato test_advanced.py con il codice seguente:
- Funzione
str_to_bool()che accetta una stringa e restituisce un valore booleano in base al contenuto della stringa. - Due test parametrizzati per la funzione
str_to_bool(), uno che testa i valoriTruee l'altro che testa i valoriFalse. - Una fixture
pytestpersonalizzata che usa la fixturetmpdir()per creare un file done temporaneo con alcuni contenuti. - Classe di test che usa la fixture personalizzata
tmpfile()per creare il file.
Tutti i test devono essere superati quando vengono eseguiti nel terminale, senza alcun errore.