Pytest: che cos’è e come funziona

di Lorenzo Neri
0 commento 11 visualizzazioni

Pytest: che cos’è e come funziona? È un framework Python che permette di realizzare test per il tuo codice e in questo articolo scopriamo come funziona.

Pytest, come scritto una frase fa, è un framework Python che permette di eseguire differenti test sul tuo codice. Non solo: è uno strumento utile e molto versatile se devi realizzare unit test oppure sei abituato a lavorare in modalità TDD, detto senza acronimi tecnichesi il “test driven development”.

Come installare Pytest

Poiché è un framework Python a tutti gli effetti, è sufficiente usare pip per installarlo:

pip install pytest

Fatto ciò, cerchiamo di capire come funziona davvero scrivendo il nostro primo test.

Come scrivere un test con Pytest

Con Pytest puoi scrivere test in modi molto differenti: il più semplice di tutti è tramite una funzione.

Per intenderci, se vuoi testare una porzione di codice, per esempio una funzione, Pytest permette di eseguire le asserzioni all’interno di funzioni ben specifiche.

Ciò che importa per far sì che funzioni tutto quanto, è che la funzione usata per eseguire il test, abbia un nome nel formato:

test_NomeDellaFunzione

Non è sufficiente: Pytest funziona in modo molto “precisino”. Significa che anche il file in cui crei il test dev’essere nominato in questo modo, altrimenti non funzionerà:

test_nomeDelFile.py

Diversamente, puoi usare anche il formato:

nomeDelFile_test.py

Facciamo un esempio:

# il codice che vuoi testare

def somma(a, b):
   return a + b

# la funzione test che verifica l'esecuzione del codice

def test_funzione_somma():
   assert somma(3,3) == 7

Se guardi bene il codice, indovina un po’? Sì, il test fallirà. Infatti per lanciare pytest e verificare l’esecuzione, devi lanciare il seguente comando.

Ipotizziamo che lo script si chiami “test_addizioni.py”:

pytest test_addizioni.py

Pytest nelle sue funzionalità ci fornisce il risultato dell’esecuzione dei test all’interno del file specificato. Per intenderci:

test_addizioni.py F                                                      [100%]

=================================== FAILURES ===================================
_____________________________ test_funzione_somma ______________________________

    def test_funzione_somma():
>      assert somma(3,3) == 7
E      assert 6 == 7
E       +  where 6 = somma(3, 3)

test_addizioni.py:9: AssertionError
FAILED test_addizioni.py::test_funzione_somma - assert 6 == 7
========================= 1 failed, 1 warning in 0.12s =========================

Per ogni test che trova, Pytest mostrerà una lettera nella prima riga che vedi: siccome abbiamo un solo test, che fallisce, avremo una sola “F”.

Non solo: lo vedi quel “100%”? Sta a indicare il progresso. Di che cosa? Di esecuzione dei test all’interno del file.

A seguito, Pytest elenca i punti dove i test eseguiti sono falliti. Nel nostro caso fallisce l’asserzione dove “supponiamo” che 3 +3 faccia 7.

Ma andiamo oltre.

Come eseguire test multipli con Pytest

Pytest funziona in modalità “greedy”, ovvero… È un golosone.

No, non ti ruberà la merenda tranquillo. Sto dicendo però che se lanci “pytest” all’interno di una cartella, si occuperà di eseguire in automatico tutti i test scritti nei file presenti dentro la cartella.

Purché questi, come abbiamo visto assieme prima, siano scritti nella forma “test_*.py” oppure “*_test.py”.

A tal proposito, ti lascio un approfondimento legato al meccanismo di individuazione test integrato in Pytest.

Ciò detto, scopriamo qualcosa in più su come funziona Pytest.

Come asserire che un’eccezione venga sollevata

Sì, suona veramente male in italiano, ma scommetto che le tue dita abbiano già cercato almeno una volta:

“Assert that an exception is raised pytest”

Se provi a tradurla, in italiano suona una po’ maluccio: ora che ci siamo chiariti, vediamo come si fa 😀

import pytest

# il codice che vuoi testare

def divisione(a, b):
   return a / b

# la funzione test che solleva l'eccezione

def test_funzione_divisione():
   with pytest.raises(Exception):
      divisione(5, 0)

E come ci si aspetta da una visione per zero:

test_divisioni.py .                                                      [100%]

=============================== warnings summary ===============================
../../Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pykwalify/core.py:7
  /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pykwalify/core.py:7: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
    import imp

-- Docs: https://docs.pytest.org/en/stable/warnings.html
========================= 1 passed, 1 warning in 0.03s =========================

Il test è passato e l’eccezione sollevata.

È molto probabile che tu ti stia chiedendo se c’è modo di racchiudere i test in modo pulito a livello di codice.

Indovina? La risposta è “sì”!

Come raggruppare test multipli in una classe

Come funziona Pytest se volessimo raggruppare dei test? Con le classi.

Per intenderci meglio:

import pytest

class TestClasse:

   # primo test

   def test_uno(self):
      assert "ciao" in "ciao, come stai?"
  
  #secondo test

   def test_due(self):
      stringa = "prova 1 2 3, sa sa"
      assert stringa != "test python"

Hai notato che ho scritto i metodi della classe sempre con la dicitura “test_*”.

Il sistema di scoperta legato ai file che abbiamo visto prima, si riflette anche per le classi.

Ciò che importa, per eseguire correttamente questi test, è che:

  • La classe, sia dichiarata come “TestNomeClasseCheTuDesideri”
  • I metodi, siano dichiarati come “test_NomeDelTestCheVuoiFare”

Se tu lanciassi:

pytest test_con_la_classe.py

Otterresti un risultato come questo:

test_con_la_classe.py ..                                                     [100%]

=============================== warnings summary ===============================
../../Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pykwalify/core.py:7
  /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pykwalify/core.py:7: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
    import imp

-- Docs: https://docs.pytest.org/en/stable/warnings.html
========================= 2 passed, 1 warning in 0.03s =========================

Hai notato che entrambi i test sono passati?

Qua però non ho detto io una cosa: quando passa un test, non avremo una lettera, ma avremo un punto. Se guardi bene la prima riga, guarda un po’ quanti ce ne sono.

Potrebbero interessarti

Lascia un commento

Questo sito potrebbe fare uso di cookie e siccome l'UE mi obbliga a fartelo presente, eccoti il classico banner dove puoi decidere come gestirli. Accetta Leggi di più