Django biedt veel testtools; in deze tutorial gebruiken we een aantal ervan om een app te testen met een aangepast gebruikersmodel en authenticatie.
We zullen de app userauth
testen die we in een eerdere tutorial hebben gemaakt. Deze bevat een aangepast gebruikersmodel en authenticatie met allauth. De opdracht om tests uit te voeren voor een specifieke app of map is:
python3 manage.py test userauth
Het argument test
is vergelijkbaar met andere argumenten die Django gebruikt, zoals runserver
, createsuperuser
, migrate
enz. Mogelijk verschijnt de volgende foutmelding:
Got an error creating the test database: permission denied to create database
Dat komt omdat Django een testdatabase zal maken, die zal worden vernietigd wanneer alle tests zijn uitgevoerd. Je moet de databasegebruiker dus toestemming geven om deze testdatabase te maken. Ga naar de psql
-opdrachtprompt:
psql postgres
en typ de volgende opdracht:
ALTER USER usr_pet CREATEDB;
waarbij usr_pet
de databasegebruiker is. Verlaat psql
met \q
.
Een andere fout die kan optreden is:
ValueError: Missing staticfiles manifest entry for 'images/favicon-32x32.png'
of iets dergelijks. Dit komt door het gebruik van ManifestStaticFilesStorage
in de parameter STATICFILES_STORAGE
in onze instellingen. Django raadt aan om deze parameter tijdens het testen op de standaardwaarde in te stellen, dus zet een comment-teken voor de regel in de instellingen waar deze parameter is gedefinieerd.
Als we nu python3 manage.py test userauth
uitvoeren, zal Django vertellen hoeveel tests zijn uitgevoerd en eventuele fouten weergeven. Zelfs zonder tests kunnen we het testcommando uitvoeren; Django zal de installatie doorlopen en wat andere dingen doen, dus zal OK teruggeven of eventuele fouten detecteren.
Er zijn veel manieren om te testen en veel artikelen over de beperkingen ervan. Twee populaire testmethoden zijn dekkingstests (bijv. met Coverage) en browserautomatisering (bijv. met Selenium). Hier beperken we ons tot dekkingstesten, die gemakkelijk kunnen worden geïntegreerd met Django. Installeer het pakket:
pip3 install coverage
Voeg het toe aan requirements.txt
en voeg coverage
toe aan INSTALLED_APPS
. Voer het uit met:
coverage run --source=userauth manage.py test userauth
De vlag source
vertelt Coverage om alleen de code in de directory userauth
te meten, en de userauth
aan het einde van de opdracht vertelt Django alleen om tests uit te voeren in de app userauth
. Het volgende commando
coverage html
maakt een directory htmlcov
aan in de projectdirectory met daarin een bestand index.html
. Klik er met de rechtermuisknop op en kies open in browser
Voor onze app userauth
zien we dat een substantieel deel van de code al bezocht is, ook zonder tests. Dat komt omdat we in onze app maximaal gebruik hebben gemaakt van de ingebouwde klassen en methoden van Django en allauth. Laten we enkele tests maken voor de stukjes code die niet werden behandeld, te beginnen met een eenvoudige: de string-representatie van het aangepaste gebruikersmodel. Teruggrijpend op onze eerdere tutorial over ons gebruikersmodel:
def __str__(self):
return f"{self.username}: {self.first_name} {self.last_name}"
We zullen Django's klasse Testcase
gebruiken. Eerst maken we een gebruiker in onze set-up met setUpTestData
, daarna testen we met assertEqual
of de string-representatie is wat het zou moeten zijn:
from .models import CustomUser
from django.test import TestCase
class TestCustomUser(TestCase):
@classmethod
def setUpTestData(cls):
cls.user = CustomUser.objects.create(username="userJohnDoe", password="secretpassword", first_name="John", last_name="Doe")
def test_string_representation_of_customuser(self):
expected_representation_customuser = "userJohnDoe: John Doe"
self.assertEqual(expected_representation_customuser, str(self.user))
Als we weer Coverage uitvoeren, blijkt dat we dat stuk code nu hebben bezocht. Dit is natuurlijk een heel eenvoudig voorbeeld. Laten we de get_absolute_url
-methode van ons model testen. Nogmaals uit onze eerdere tutorial:
def get_absolute_url(self):
return reverse('account_profile')
met het volgende in onze urls.py
:
path('profile/', profile_view, name='account_profile'),
en in onze views.py
:
def profile_view(request):
return render(request, 'account/profile.html')
Een call naar profile_view
met een ingelogde gebruiker moet een geldig antwoord geven. De Django-documentatie beschrijft hoe een gebruikerslogin kan worden gesimuleerd met RequestFactory
, dat een request
-object genereert. We importeren RequestFactory
en profile_view
:
from .views import profile_view
from django.test import RequestFactory
In onze setUpTestData
voegen we de regel toe:
cls.factory = RequestFactory()
en dan is onze test (met behulp van het HttpResponse
-attribuut status_code
):
def test_profile_view_with_user_gets_valid_response(self):
request = self.factory.get(self.user.get_absolute_url())
# log user in
request.user = self.user
self.assertEqual(profile_view(request).status_code, 200)
Onze laatste test voor userauth
is voor LoginForm
in forms.py
. Definieer een tweede gebruiker in setUpTestData
:
cls.user2 = CustomUser.objects.create(username="undefined", password="undefined", first_name="undefined", last_name="undefined")
We kunnen de eerste gebruiker niet hergebruiken, omdat de tests niet noodzakelijkerwijs worden uitgevoerd in de volgorde waarin ze zijn gedefinieerd, wat betekent dat wijzigingen in de ene test van invloed kunnen zijn op hergebruikte variabelen in een andere. Definieer wat formuliergegevens, voer deze in in SignupForm
en gebruik de signup
methode van het formulier voor de nieuw gemaakte gebruiker om te controleren of de methode doet wat hij moet doen:
def test_signup_form(self):
form_data = {'first_name': "Jane", 'last_name': "Doe", 'display_name': "Jane Doe"}
form = SignupForm(data=form_data)
self.assertTrue(form.is_valid())
form.signup(self, user=self.user2)
self.assertEqual(self.user2.display_name, "Jane Doe")
coverage
opnieuw uitvoeren laat zien dat we meer dan 95% van de code van userauth
hebben behandeld en dat slechts enkele eenvoudige coderegels ontbreken. We beëindigen het testen van deze app en gaan verder met de volgende.
Reageer op dit artikel (log eerst in of bevestig hieronder met naam en email)