🚀 Nuova versione beta disponibile! Feedback o problemi? Contattaci

Test Unitari in Python

Codegrind Team•Sep 11 2024

I test unitari sono un metodo per verificare che le singole unitĂ  di codice (come funzioni o classi) funzionino come previsto. In Python, il modulo integrato unittest fornisce un framework potente e flessibile per scrivere e eseguire test automatizzati. Con i test unitari, puoi individuare bug e problemi prima che il tuo codice venga distribuito, garantendo la qualitĂ  e la stabilitĂ  del software.

In questo articolo esploreremo come scrivere test unitari, eseguirli e analizzare i risultati, oltre a buone pratiche per il testing.

1. Cos’è un Test Unitario?

Un test unitario è una verifica automatizzata che assicura che una funzione, metodo o classe in un programma Python si comporti come previsto in condizioni controllate. I test unitari:

  • Validano piccole unitĂ  di funzionalitĂ  in modo isolato.
  • Forniscono una base solida per il refactoring del codice.
  • Riduccono il rischio di introdurre bug quando si aggiungono nuove funzionalitĂ .

2. Il Modulo unittest

Il modulo unittest è un framework integrato in Python per scrivere e organizzare test. Offre strumenti per creare test, raggrupparli in classi, eseguire i test e verificare i risultati.

Importare il Modulo unittest

import unittest

3. Scrivere un Test Unitario di Base

Vediamo un esempio di come creare un semplice test unitario per una funzione che somma due numeri.

Funzione da Testare

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

Scrivere un Test per la Funzione

Per scrivere un test per la funzione somma(), creiamo una classe che eredita da unittest.TestCase e definiamo i metodi di test.

import unittest
from mio_modulo import somma  # Importa la funzione da testare

class TestSomma(unittest.TestCase):

    def test_somma_positivi(self):
        self.assertEqual(somma(2, 3), 5)

    def test_somma_negativi(self):
        self.assertEqual(somma(-1, -1), -2)

    def test_somma_zero(self):
        self.assertEqual(somma(0, 0), 0)

# Eseguire i test se il file viene eseguito direttamente
if __name__ == '__main__':
    unittest.main()

Spiegazione:

  • TestSomma: Una classe che rappresenta il gruppo di test. Eredita da unittest.TestCase.
  • test_somma_positivi, test_somma_negativi, test_somma_zero: Ogni metodo che inizia con test_ viene eseguito automaticamente da unittest come un test.
  • self.assertEqual(): Un metodo per verificare che il risultato della funzione sia uguale al valore atteso.

4. Eseguire i Test

Per eseguire i test, puoi semplicemente eseguire il file Python contenente i test. Se i test passano, vedrai un output simile a questo:

$ python test_mio_modulo.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.001s

OK

Se un test fallisce, l’output mostrerà dettagli sull’errore:

$ python test_mio_modulo.py
F..
======================================================================
FAIL: test_somma_positivi (test_mio_modulo.TestSomma)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_mio_modulo.py", line 6, in test_somma_positivi
    self.assertEqual(somma(2, 3), 6)
AssertionError: 5 != 6

5. Altri Metodi di Verifica

Oltre a assertEqual(), unittest fornisce diversi metodi per testare le condizioni.

Metodi Comuni di unittest

  • assertEqual(a, b): Verifica che a sia uguale a b.
  • assertNotEqual(a, b): Verifica che a non sia uguale a b.
  • assertTrue(x): Verifica che x sia True.
  • assertFalse(x): Verifica che x sia False.
  • assertIsNone(x): Verifica che x sia None.
  • assertIsInstance(a, b): Verifica che a sia un’istanza di b.

Esempio di Altri Test

import unittest

def is_pari(n):
    return n % 2 == 0

class TestIsPari(unittest.TestCase):

    def test_pari(self):
        self.assertTrue(is_pari(4))

    def test_dispari(self):
        self.assertFalse(is_pari(3))

    def test_valore_none(self):
        self.assertIsNone(None)

if __name__ == '__main__':
    unittest.main()

6. Testare Eccezioni

Puoi usare il metodo assertRaises() per verificare che una determinata eccezione venga sollevata da una funzione.

Esempio di Test di Eccezioni

def dividi(a, b):
    if b == 0:
        raise ValueError("Divisione per zero non consentita")
    return a / b

class TestDividi(unittest.TestCase):

    def test_divisione_zero(self):
        with self.assertRaises(ValueError):
            dividi(10, 0)

if __name__ == '__main__':
    unittest.main()

In questo esempio, il test verifica che venga sollevata un’eccezione ValueError quando si tenta di dividere per zero.

7. Setup e Teardown

In alcuni casi, potresti voler eseguire del codice prima o dopo ogni test, come ad esempio preparare un database o chiudere delle risorse. Puoi usare i metodi setUp() e tearDown() per questo scopo.

Esempio di Setup e Teardown

class TestConSetupTeardown(unittest.TestCase):

    def setUp(self):
        # Codice da eseguire prima di ogni test
        self.lista = [1, 2, 3]

    def tearDown(self):
        # Codice da eseguire dopo ogni test
        self.lista = None

    def test_aggiunta_elemento(self):
        self.lista.append(4)
        self.assertEqual(self.lista, [1, 2, 3, 4])

if __name__ == '__main__':
    unittest.main()

Spiegazione:

  • setUp(): Viene eseguito prima di ogni test. In questo caso, prepara una lista.
  • tearDown(): Viene eseguito dopo ogni test. In questo esempio, pulisce la lista.

8. Eseguire Test con pytest

Oltre a unittest, puoi utilizzare il popolare framework pytest, che offre una sintassi piĂą semplice e funzionalitĂ  avanzate per scrivere test. Per usare pytest, devi prima installarlo:

pip install pytest

Poi puoi scrivere test simili a quelli di unittest, ma senza la necessitĂ  di usare una classe.

Esempio di Test con pytest

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

def test_somma_positivi():
    assert somma(2, 3) == 5

def test_somma_negativi():
    assert somma(-1, -1) == -2

Per eseguire i test, basta eseguire il comando:

pytest

9. Buone Pratiche per i Test Unitari

  • Testare solo una cosa alla volta: Ogni test dovrebbe verificare una singola unitĂ  di funzionalitĂ .
  • Evitare test complessi: Mantieni i tuoi test semplici e facili da capire.
  • Isolare i test: I test unitari non dovrebbero dipendere l’uno dall’altro.
  • Eseguire test regolarmente: Esegui i test ogni volta che modifichi il codice, per identificare subito eventuali problemi.

Conclusione

I test unitari sono un elemento fondamentale per garantire la qualità e la stabilità del codice. Python fornisce un framework integrato, unittest, che permette di creare test in modo semplice ed efficace. Con il giusto approccio e l’uso di strumenti come pytest, puoi migliorare la manutenibilità e l’affidabilità del tuo software.