Testing
Il testing e una pratica fondamentale per garantire la qualita e lâaffidabilita di unâapplicazione Django. Il framework include un sistema di testing completo basato su unittest di Python, con strumenti specifici per testare modelli, viste, form e API.
Classi di Test Disponibili
Django mette a disposizione diverse classi di test, ognuna con caratteristiche specifiche:
- SimpleTestCase: Per test che non necessitano di accesso al database.
- TestCase: La piu utilizzata, con transazioni e database di test.
- TransactionTestCase: Per test che richiedono il controllo delle transazioni.
- LiveServerTestCase: Avvia un server di test reale, utile per test con Selenium.
Primo Test con TestCase
# myapp/tests.py
from django.test import TestCase
from .models import Articolo
class ArticoloTestCase(TestCase):
def setUp(self):
"""Eseguito prima di ogni metodo di test."""
self.articolo = Articolo.objects.create(
titolo="Test Articolo",
contenuto="Contenuto di prova",
pubblicato=True,
)
def tearDown(self):
"""Eseguito dopo ogni metodo di test."""
# La pulizia del database avviene automaticamente con TestCase
pass
def test_creazione_articolo(self):
"""Verifica che l'articolo sia stato creato correttamente."""
self.assertEqual(self.articolo.titolo, "Test Articolo")
self.assertTrue(self.articolo.pubblicato)
def test_conteggio_articoli(self):
"""Verifica il numero di articoli nel database."""
conteggio = Articolo.objects.count()
self.assertEqual(conteggio, 1)
def test_stringa_rappresentazione(self):
"""Verifica il metodo __str__ del modello."""
self.assertEqual(str(self.articolo), "Test Articolo")
Esegui i test:
python manage.py test
python manage.py test myapp # Test di una singola app
python manage.py test myapp.tests.ArticoloTestCase # Test di una singola classe
python manage.py test myapp.tests.ArticoloTestCase.test_creazione_articolo # Singolo test
Test delle Viste con Client
Il Client di Django simula un browser web per testare le viste:
from django.test import TestCase, Client
from django.urls import reverse
class VisteTestCase(TestCase):
def setUp(self):
self.client = Client()
Articolo.objects.create(
titolo="Articolo Test",
contenuto="Contenuto",
pubblicato=True,
)
def test_lista_articoli(self):
"""Verifica che la pagina della lista articoli funzioni."""
response = self.client.get(reverse("lista-articoli"))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "articoli/lista.html")
self.assertContains(response, "Articolo Test")
def test_dettaglio_articolo(self):
"""Verifica la pagina di dettaglio."""
response = self.client.get(reverse("dettaglio-articolo", args=[1]))
self.assertEqual(response.status_code, 200)
def test_pagina_non_trovata(self):
"""Verifica il comportamento per una pagina inesistente."""
response = self.client.get(reverse("dettaglio-articolo", args=[999]))
self.assertEqual(response.status_code, 404)
def test_creazione_articolo_post(self):
"""Verifica la creazione di un articolo tramite POST."""
response = self.client.post(reverse("crea-articolo"), {
"titolo": "Nuovo Articolo",
"contenuto": "Nuovo contenuto",
})
self.assertEqual(response.status_code, 302) # Redirect dopo creazione
self.assertTrue(Articolo.objects.filter(titolo="Nuovo Articolo").exists())
Test con Autenticazione
from django.contrib.auth.models import User
class VisteAutenticateTestCase(TestCase):
def setUp(self):
self.utente = User.objects.create_user(
username="testuser",
password="testpass123",
)
def test_accesso_area_privata(self):
"""Verifica che l'area privata richieda autenticazione."""
response = self.client.get(reverse("dashboard"))
self.assertEqual(response.status_code, 302) # Redirect al login
self.client.login(username="testuser", password="testpass123")
response = self.client.get(reverse("dashboard"))
self.assertEqual(response.status_code, 200)
RequestFactory
RequestFactory crea oggetti request senza passare attraverso il middleware, utile per testare le viste in isolamento:
from django.test import TestCase, RequestFactory
from .views import lista_articoli
class RequestFactoryTestCase(TestCase):
def setUp(self):
self.factory = RequestFactory()
def test_lista_articoli_view(self):
request = self.factory.get("/articoli/")
request.user = User.objects.create_user(username="test", password="test123")
response = lista_articoli(request)
self.assertEqual(response.status_code, 200)
SimpleTestCase per Test Senza Database
from django.test import SimpleTestCase
from django.urls import reverse, resolve
from .views import homepage
class URLTestCase(SimpleTestCase):
def test_homepage_url(self):
url = reverse("homepage")
self.assertEqual(resolve(url).func, homepage)
def test_url_status(self):
response = self.client.get("/")
self.assertEqual(response.status_code, 200)
Fixture e Dati di Test
Puoi caricare dati predefiniti usando le fixture:
class ArticoloConFixtureTestCase(TestCase):
fixtures = ["articoli_test.json"]
def test_articoli_caricati(self):
self.assertEqual(Articolo.objects.count(), 5)
Metodi di Asserzione Utili
Django estende le asserzioni standard con metodi specifici:
# Asserzioni sulle risposte HTTP
self.assertContains(response, "testo atteso")
self.assertNotContains(response, "testo non atteso")
self.assertTemplateUsed(response, "template.html")
self.assertRedirects(response, "/destinazione/")
# Asserzioni sui form
self.assertFormError(response, "form", "campo", "Errore atteso")
# Asserzioni sulle query
self.assertQuerySetEqual(qs, ["valore1", "valore2"])
self.assertNumQueries(3, lambda: lista_articoli())
Conclusione
Il framework di testing di Django offre tutti gli strumenti necessari per scrivere test completi e affidabili. Usa TestCase per i test standard, Client per simulare le richieste HTTP, RequestFactory per testare le viste in isolamento e SimpleTestCase quando non serve il database. Testare regolarmente il codice previene regressioni e migliora la qualita complessiva dellâapplicazione.