TestverktygLink to this heading

Django tillhandahåller en liten uppsättning verktyg som är användbara när du skriver tester.

TestklientenLink to this heading

Testklienten är en Python-klass som fungerar som en dummy-webbläsare, så att du kan testa dina vyer och interagera med din Django-drivna applikation programmatiskt.

Några av de saker du kan göra med testklienten är följande:

  • Simulera GET- och POST-begäranden på en URL och observera svaret - allt från HTTP på låg nivå (resultathuvuden och statuskoder) till sidinnehåll.

  • Se kedjan av omdirigeringar (om det finns några) och kontrollera webbadressen och statuskoden i varje steg.

  • Testa att en given begäran återges av en given Django-mall, med en mallkontext som innehåller vissa värden.

Observera att testklienten inte är avsedd att ersätta Selenium eller andra ramverk ”i webbläsaren”. Djangos testklient har ett annat fokus. Kort och gott:

  • Använd Djangos testklient för att fastställa att rätt mall återges och att mallen får rätt kontextdata.

  • Använd RequestFactory för att testa vyfunktioner direkt, förbi routing- och middleware-lagren.

  • Använd ramverk i webbläsaren som Selenium för att testa renderad HTML och beteendet på webbsidor, nämligen JavaScript-funktionalitet. Django ger också särskilt stöd för dessa ramverk; se avsnittet om LiveServerTestCase för mer information.

En omfattande testsvit bör använda en kombination av alla dessa testtyper.

Översikt och ett snabbt exempelLink to this heading

För att använda testklienten, instansiera django.test.Client och hämta webbsidor:

Python console
>>> from django.test import Client
>>> c = Client()
>>> response = c.post("/login/", {"username": "john", "password": "smith"})
>>> response.status_code
200
>>> response = c.get("/customer/details/")
>>> response.content
b'<!DOCTYPE html...'

Som exemplet visar kan du instansiera Client från en session i den interaktiva Python-tolken.

Notera några viktiga saker om hur testklienten fungerar:

  • Testklienten kräver inte att webbservern är igång. Faktum är att det går alldeles utmärkt utan att någon webbserver körs alls! Det beror på att den undviker HTTP:s overhead och hanterar Django-ramverket direkt. Detta hjälper till att få enhetstesterna att köras snabbt.

  • När du hämtar sidor ska du komma ihåg att ange sökvägen i URL:en, inte hela domänen. Detta är till exempel korrekt:

    Python console
    >>> c.get("/login/")
    

    Detta är felaktigt:

    Python console
    >>> c.get("https://www.example.com/login/")
    

    Testklienten kan inte hämta webbsidor som inte drivs av ditt Django-projekt. Om du behöver hämta andra webbsidor kan du använda en modul från Pythons standardbibliotek, t.ex. urllib.

  • För att lösa URL:er använder testklienten den URLconf som pekas ut av din inställning ROOT_URLCONF.

  • Även om ovanstående exempel skulle fungera i Pythons interaktiva tolk, är en del av testklientens funktionalitet, särskilt den mallrelaterade funktionaliteten, endast tillgänglig när tester körs.

    Anledningen till detta är att Djangos testlöpare utför lite svart magi för att avgöra vilken mall som laddades av en viss vy. Denna svarta magi (i huvudsak en patchning av Djangos mallsystem i minnet) sker endast under testkörning.

  • Som standard kommer testklienten att inaktivera alla CSRF-kontroller som utförs av din webbplats.

    Om du av någon anledning vill att testklienten ska utföra CSRF-kontroller kan du skapa en instans av testklienten som tvingar fram CSRF-kontroller. För att göra detta, skicka in argumentet enforce_csrf_checks när du konstruerar din klient:

    Python console
    >>> from django.test import Client
    >>> csrf_client = Client(enforce_csrf_checks=True)
    

Att göra förfrågningarLink to this heading

Använd klassen django.test.Client för att göra förfrågningar.

class Client(enforce_csrf_checks=False, raise_request_exception=True, json_encoder=DjangoJSONEncoder, *, headers=None, query_params=None, **defaults)Link to this definition

En testande HTTP-klient. Tar emot flera argument som kan anpassa beteendet.

med headers kan du ange standardrubriker som ska skickas med varje begäran. Till exempel, för att ställa in en User-Agent header:

Code
client = Client(headers={"user-agent": "curl/7.79.1"})

med query_params kan du ange standardfrågesträngen som kommer att ställas in vid varje förfrågan.

Godtyckliga nyckelordsargument i **defaults ställer in WSGI environ-variabler. Till exempel, för att ställa in skriptnamnet:

Code
client = Client(SCRIPT_NAME="/app/")

The values from the headers, query_params, and extra keyword arguments passed to get(), post(), etc. have precedence over the defaults passed to the class constructor.

Argumentet enforce_csrf_checks kan användas för att testa CSRF-skydd (se ovan).

Argumentet raise_request_exception gör det möjligt att kontrollera om undantag som uppstår under begäran också ska uppstå i testet. Standardvärdet är True.

Argumentet json_encoder gör det möjligt att ange en anpassad JSON-kodare för JSON-serialiseringen som beskrivs i post().

När du har en Client-instans kan du anropa någon av följande metoder:

get(path, data=None, follow=False, secure=False, *, headers=None, query_params=None, **extra)Link to this definition

Gör en GET-begäran på den angivna path och returnerar ett Response-objekt, som dokumenteras nedan.

Nyckel-värdeparen i ordlistan query_params används för att ställa in frågesträngar. Ett exempel:

Python console
>>> c = Client()
>>> c.get("/customers/details/", query_params={"name": "fred", "age": 7})

…kommer att resultera i en utvärdering av en GET-begäran som motsvarar:

Text
/customers/details/?name=fred&age=7

Det är också möjligt att skicka dessa parametrar till parametern data. query_params är dock att föredra eftersom den fungerar för alla HTTP-metoder.

Parametern headers kan användas för att ange vilka rubriker som ska skickas i begäran. Till exempel:

Python console
>>> c = Client()
>>> c.get(
...     "/customers/details/",
...     query_params={"name": "fred", "age": 7},
...     headers={"accept": "application/json"},
... )

…will send the HTTP header HTTP_ACCEPT to the details view, which is a good way to test code paths that use the django.http.HttpRequest.accepts() method.

Godtyckliga nyckelordsargument ställer in WSGI environ-variabler. Till exempel headers för att ange skriptnamnet:

Python console
>>> c = Client()
>>> c.get("/", SCRIPT_NAME="/app/")

Om du redan har GET-argumenten i URL-kodad form kan du använda den kodningen i stället för att använda data-argumentet. Till exempel kan den föregående GET-begäran också ställas som:

Python console
>>> c = Client()
>>> c.get("/customers/details/?name=fred&age=7")

Om du anger en URL med både kodade GET-data och antingen ett query_params- eller data-argument kommer dessa argument att ha företräde.

Om du anger follow till True kommer klienten att följa alla omdirigeringar och ett redirect_chain-attribut kommer att anges i svarsobjektet som innehåller tuples av de mellanliggande webbadresserna och statuskoderna.

Om du hade en URL /redirect_me/ som omdirigerades till /next/, som omdirigerades till /final/, är det här vad du skulle se:

Python console
>>> response = c.get("/redirect_me/", follow=True)
>>> response.redirect_chain
[('http://testserver/next/', 302), ('http://testserver/final/', 302)]

Om du anger secure till True kommer klienten att emulera en HTTPS-begäran.

post(path, data=None, content_type=MULTIPART_CONTENT, follow=False, secure=False, *, headers=None, query_params=None, **extra)Link to this definition

Gör en POST-begäran på den angivna path och returnerar ett Response-objekt, som dokumenteras nedan.

Nyckel-värdeparen i ordlistan data används för att skicka POST-data. Till exempel:

Python console
>>> c = Client()
>>> c.post("/login/", {"name": "fred", "passwd": "secret"})

…kommer att resultera i en utvärdering av en POST-begäran till denna URL:

Text
/login/

…med denna POST-data:

Text
name=fred&passwd=secret

Om du anger content_type som application/json, serialiseras data med json.dumps() om det är en dict, lista eller tuple. Serialisering utförs med DjangoJSONEncoder som standard, och kan åsidosättas genom att tillhandahålla ett json_encoder argument till Client. Denna serialisering sker också för put(), patch() och delete() förfrågningar.

Om du anger någon annan content_type (t.ex. text/xml för en XML-nyttolast) skickas innehållet i data som det är i POST-begäran, med content_type i HTTP-rubriken Content-Type.

Om du inte anger något värde för content_type kommer värdena i data att överföras med en innehållstyp av multipart/form-data. I det här fallet kommer nyckel-värdeparen i data att kodas som ett multipartmeddelande och användas för att skapa POST-datanyttolasten.

Om du vill skicka in flera värden för en viss nyckel - t.ex. för att ange urvalen för en <select multiple> - ska du ange värdena som en lista eller tupel för den nyckel som krävs. Till exempel skulle detta värde av data skicka tre valda värden för fältet med namnet choices:

Code
{"choices": ["a", "b", "d"]}

Att skicka filer är ett specialfall. För att POSTa en fil behöver du bara ange filfältets namn som en nyckel och ett filhandtag till filen du vill ladda upp som ett värde. Om ditt formulär till exempel har fälten name och attachment, är det senare en FileField:

Python console
>>> c = Client()
>>> with open("wishlist.doc", "rb") as fp:
...     c.post("/customers/wishes/", {"name": "fred", "attachment": fp})
...

Du kan också tillhandahålla vilket filliknande objekt som helst (t.ex. StringIO eller BytesIO) som ett filhandtag. Om du laddar upp till en ImageField behöver objektet ett name-attribut som skickar validate_image_file_extension-validatorn. Till exempel:

Python console
>>> from io import BytesIO
>>> img = BytesIO(
...     b"GIF89a\x01\x00\x01\x00\x00\x00\x00!\xf9\x04\x01\x00\x00\x00"
...     b"\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x01\x00\x00"
... )
>>> img.name = "myimage.gif"

Observera att om du vill använda samma filhandtag för flera post()-anrop måste du manuellt återställa filpekaren mellan inläggen. Det enklaste sättet att göra detta är att manuellt stänga filen efter att den har levererats till post(), som demonstreras ovan.

Du bör också se till att filen öppnas på ett sätt som gör det möjligt att läsa data. Om filen innehåller binära data, t.ex. en bild, innebär det att du måste öppna filen i läget rb (read binary).

Parametrarna headers, query_params och extra fungerar på samma sätt som för Client.get().

Om URL:en som du begär med en POST innehåller kodade parametrar, kommer dessa parametrar att göras tillgängliga i request.GET-data. Om du t.ex. skulle göra begäran:

Python console
>>> c.post(
...     "/login/", {"name": "fred", "passwd": "secret"}, query_params={"visitor": "true"}
... )

… kan vyn som hanterar denna begäran fråga request.POST för att hämta användarnamn och lösenord, och kan fråga request.GET för att avgöra om användaren var en besökare.

Om du anger follow till True kommer klienten att följa alla omdirigeringar och ett redirect_chain-attribut kommer att anges i svarsobjektet som innehåller tuples av de mellanliggande webbadresserna och statuskoderna.

Om du anger secure till True kommer klienten att emulera en HTTPS-begäran.

head(path, data=None, follow=False, secure=False, *, headers=None, query_params=None, **extra)Link to this definition

Gör en HEAD-förfrågan på den angivna path och returnerar ett Response-objekt. Denna metod fungerar precis som Client.get(), inklusive parametrarna follow, secure, headers, query_params och extra, förutom att den inte returnerar en meddelandekropp.

options(path, data='', content_type='application/octet-stream', follow=False, secure=False, *, headers=None, query_params=None, **extra)Link to this definition

Gör en OPTIONS-begäran på den angivna vägen och returnerar ett svar-objekt. Användbart för att testa RESTful-gränssnitt.

När data tillhandahålls används det som förfrågningsunderlag och ett Content-Type-huvud sätts till content_type.

Parametrarna follow, secure, headers, query_params och extra fungerar på samma sätt som för Client.get().

put(path, data='', content_type='application/octet-stream', follow=False, secure=False, *, headers=None, query_params=None, **extra)Link to this definition

Gör en PUT-förfrågan på den angivna path och returnerar ett Response-objekt. Användbart för att testa RESTful-gränssnitt.

När data tillhandahålls används det som förfrågningsunderlag och ett Content-Type-huvud sätts till content_type.

Parametrarna follow, secure, headers, query_params och extra fungerar på samma sätt som för Client.get().

patch(path, data='', content_type='application/octet-stream', follow=False, secure=False, *, headers=None, query_params=None, **extra)Link to this definition

Gör en PATCH-förfrågan på den angivna banan och returnerar ett svar-objekt. Användbart för att testa RESTful-gränssnitt.

Parametrarna follow, secure, headers, query_params och extra fungerar på samma sätt som för Client.get().

delete(path, data='', content_type='application/octet-stream', follow=False, secure=False, *, headers=None, query_params=None, **extra)Link to this definition

Gör en DELETE-begäran på den angivna vägen och returnerar ett svar-objekt. Användbart för att testa RESTful-gränssnitt.

När data tillhandahålls används det som förfrågningsunderlag och ett Content-Type-huvud sätts till content_type.

Parametrarna follow, secure, headers, query_params och extra fungerar på samma sätt som för Client.get().

trace(path, follow=False, secure=False, *, headers=None, query_params=None, **extra)Link to this definition

Gör en TRACE-begäran på den angivna vägen och returnerar ett svar-objekt. Användbar för att simulera diagnostiska prober.

Till skillnad från de andra förfrågningsmetoderna tillhandahålls inte data som en nyckelordsparameter för att följa RFC 9110 Section 9.3.8, som föreskriver att TRACE-förfrågningar inte får ha en kropp.

Parametrarna follow, secure, headers, query_params och extra fungerar på samma sätt som för Client.get().

login(**credentials)Link to this definition
alogin(**credentials)Link to this definition

Asynkron version: alogin()

Om din webbplats använder Djangos authentication system och du hanterar inloggning av användare, kan du använda testklientens login()-metod för att simulera effekten av att en användare loggar in på webbplatsen.

När du anropar den här metoden kommer testklienten att ha alla cookies och sessionsdata som krävs för att klara inloggningsbaserade tester som kan ingå i en vy.

Formatet på argumentet credentials beror på vilken authentication backend <authentication-backends>` du använder (som konfigureras av din AUTHENTICATION_BACKENDS-inställning). Om du använder standardautentiseringsbackend som tillhandahålls av Django (ModelBackend), bör credentials vara användarens användarnamn och lösenord, som tillhandahålls som nyckelordsargument:

Python console
>>> c = Client()
>>> c.login(username="fred", password="secret")

# Now you can access a view that's only available to logged-in users.

Om du använder en annan autentiseringsbackend kan den här metoden kräva andra referenser. Den kräver de autentiseringsuppgifter som krävs av din backends authenticate() metod.

login() returns True if the credentials were accepted and login was successful.

Finally, you’ll need to remember to create user accounts before you can use this method. As we explained above, the test runner is executed using a test database, which contains no users by default. As a result, user accounts that are valid on your production site will not work under test conditions. You’ll need to create users as part of the test suite – either manually (using the Django model API) or with a test fixture. Remember that if you want your test user to have a password, you can’t set the user’s password by setting the password attribute directly – you must use the set_password() function to store a correctly hashed password. Alternatively, you can use the create_user() helper method to create a new user with a correctly hashed password.

force_login(user, backend=None)Link to this definition
aforce_login(user, backend=None)Link to this definition

Asynkron version: aforce_login()

Om din webbplats använder Djangos authentication system kan du använda metoden force_login() för att simulera effekten av att en användare loggar in på webbplatsen. Använd den här metoden istället för login() när ett test kräver att en användare är inloggad och detaljerna om hur en användare loggar in inte är viktiga.

Till skillnad från login() hoppar den här metoden över autentiserings- och verifieringsstegen: inaktiva användare (is_active=False) tillåts logga in och användarens autentiseringsuppgifter behöver inte anges.

Användaren kommer att ha sitt backend-attribut inställt till värdet av backend-argumentet (som bör vara en prickad Python-sökvägssträng), eller till settings.AUTHENTICATION_BACKENDS[0] om ett värde inte tillhandahålls. Funktionen authenticate() som anropas av login() annoterar normalt användaren så här.

Den här metoden är snabbare än login() eftersom de dyra hashingalgoritmerna för lösenord kringgås. Du kan också snabba upp login() genom att använda en svagare hasher när du testar.

logout()Link to this definition
alogout()Link to this definition

Asynkron version: alogout()

Om din webbplats använder Djangos autentiseringssystem, kan metoden logout() användas för att simulera effekten av att en användare loggar ut från din webbplats.

När du har anropat den här metoden kommer testklienten att ha alla cookies och sessionsdata rensade till standardvärden. Efterföljande förfrågningar kommer att se ut att komma från en AnonymousUser.

Testning av svarLink to this heading

Metoderna get() och post() returnerar båda ett Response-objekt. Detta Response-objekt är inte samma som HttpResponse-objektet som returneras av Django-vyer; testsvarsobjektet har några ytterligare data som är användbara för testkod för att verifiera.

Specifikt har ett Response-objekt följande attribut:

class ResponseLink to this definition
clientLink to this definition

Den testklient som användes för att göra den begäran som resulterade i svaret.

contentLink to this definition

Svarets innehåll, som en bytestring. Detta är det slutliga sidinnehållet som återges av vyn, eller ett eventuellt felmeddelande.

contextLink to this definition

Mallen Context-instans som användes för att rendera den mall som producerade svarsinnehållet.

Om den renderade sidan använde flera mallar kommer context att vara en lista med Context-objekt, i den ordning de renderades.

Oavsett hur många mallar som används vid rendering kan du hämta kontextvärden med operatorn []. Exempelvis kan kontextvariabeln name hämtas med hjälp av:

Python console
>>> response = client.get("/foo/")
>>> response.context["name"]
'Arthur'
exc_infoLink to this definition

En tupel med tre värden som ger information om det eventuella ohanterade undantag som inträffade under vyn.

Värdena är (type, value, traceback), samma som returneras av Pythons sys.exc_info(). Deras betydelser är:

  • typ: Typ av undantag.

  • värde: Instansen för undantaget.

  • traceback: Ett traceback-objekt som kapslar in anropsstacken vid den punkt där undantaget ursprungligen inträffade.

Om inget undantag inträffade kommer exc_info att vara None.

json(**kwargs)Link to this definition

Svarets text, tolkad som JSON. Extra nyckelordsargument skickas till json.loads(). Till exempel: json.loads:

Python console
>>> response = client.get("/foo/")
>>> response.json()["name"]
'Arthur'

Om rubriken Content-Type inte är "application/json", kommer ett ValueError` att uppstå när du försöker analysera svaret.

requestLink to this definition

Förfrågningsdata som stimulerade svaret.

wsgi_requestLink to this definition

Instansen WSGIRequest som genererades av testhanteraren som genererade svaret.

status_codeLink to this definition

HTTP-status för svaret, som ett heltal. För en fullständig lista över definierade koder, se IANA status code registry.

templatesLink to this definition

En lista över Template-instanser som används för att rendera det slutliga innehållet, i den ordning de renderades. För varje mall i listan, använd template.name för att få mallens filnamn, om mallen laddades från en fil. (Namnet är en sträng som till exempel 'admin/index.html'.)

resolver_matchLink to this definition

En instans av ResolverMatch för svaret. Du kan till exempel använda attributet func för att verifiera den vy som serverade svaret:

Code
# my_view here is a function based view.
self.assertEqual(response.resolver_match.func, my_view)

# Class-based views need to compare the view_class, as the
# functions generated by as_view() won't be equal.
self.assertIs(response.resolver_match.func.view_class, MyView)

Om den angivna URL:en inte hittas kommer åtkomst till detta attribut att ge upphov till ett Resolver404 undantag.

Precis som med ett vanligt svar kan du också komma åt rubrikerna via HttpResponse.headers. Du kan till exempel bestämma innehållstypen i ett svar med hjälp av response.headers['Content-Type'].

UndantagLink to this heading

Om du riktar testklienten mot en vy som ger upphov till ett undantag och Client.raise_request_exception är True, kommer undantaget att vara synligt i testfallet. Du kan sedan använda ett standardblock try ... except eller assertRaises() för att testa för undantag.

De enda undantagen som inte är synliga för testklienten är Http404, PermissionDenied, SystemExit, och SuspiciousOperation. Django fångar dessa undantag internt och omvandlar dem till lämpliga HTTP-svarskoder. I dessa fall kan du kontrollera response.status_code i ditt test.

Om Client.raise_request_exception är False kommer testklienten att returnera ett 500-svar som skulle returneras till en webbläsare. Svaret har attributet exc_info för att ge information om det ohanterade undantaget.

Beständigt tillståndLink to this heading

Testklienten är tillståndsbaserad. Om ett svar returnerar en cookie, kommer denna cookie att lagras i testklienten och skickas med alla efterföljande get()- och post()-förfrågningar.

Utgångspolicyerna för dessa cookies följs inte. Om du vill att en cookie ska upphöra att gälla måste du antingen ta bort den manuellt eller skapa en ny instans av Client (vilket i praktiken innebär att alla cookies tas bort).

En testklient har attribut som lagrar information om beständigt tillstånd. Du kan komma åt dessa egenskaper som en del av ett testvillkor.

Client.cookiesLink to this definition

Ett Python SimpleCookie-objekt som innehåller de aktuella värdena för alla klientcookies. Se dokumentationen för modulen http.cookies för mer information.

Client.sessionLink to this definition

Ett ordboksliknande objekt som innehåller sessionsinformation. Se session documentation för fullständig information.

För att ändra sessionen och sedan spara den måste den först lagras i en variabel (eftersom en ny SessionStore skapas varje gång denna egenskap används):

Code
def test_something(self):
    session = self.client.session
    session["somekey"] = "test"
    session.save()
Client.asession()Link to this definition

Detta liknar attributet session men det fungerar i asynkrona sammanhang.

Ställa in språkLink to this heading

När du testar applikationer som stöder internationalisering och lokalisering kanske du vill ställa in språket för en testklientbegäran. Metoden för att göra detta beror på om LocaleMiddleware är aktiverad eller inte.

Om middleware är aktiverat kan språket ställas in genom att skapa en cookie med namnet LANGUAGE_COOKIE_NAME och ett värde som motsvarar språkkoden:

Code
from django.conf import settings


def test_language_using_cookie(self):
    self.client.cookies.load({settings.LANGUAGE_COOKIE_NAME: "fr"})
    response = self.client.get("/")
    self.assertEqual(response.content, b"Bienvenue sur mon site.")

eller genom att inkludera HTTP-huvudet Accept-Language i begäran:

Code
def test_language_using_header(self):
    response = self.client.get("/", headers={"accept-language": "fr"})
    self.assertEqual(response.content, b"Bienvenue sur mon site.")

Mer information finns i Hur Django upptäcker språkpreferenser.

Om mellanvaran inte är aktiverad kan det aktiva språket ställas in med translation.override():

Code
from django.utils import translation


def test_language_using_override(self):
    with translation.override("fr"):
        response = self.client.get("/")
    self.assertEqual(response.content, b"Bienvenue sur mon site.")

Mer information finns i Explicit inställning av det aktiva språket.

ExempelLink to this heading

Följande är ett enhetstest med hjälp av testklienten:

Code
import unittest
from django.test import Client


class SimpleTest(unittest.TestCase):
    def setUp(self):
        # Every test needs a client.
        self.client = Client()

    def test_details(self):
        # Issue a GET request.
        response = self.client.get("/customer/details/")

        # Check that the response is 200 OK.
        self.assertEqual(response.status_code, 200)

        # Check that the rendered context contains 5 customers.
        self.assertEqual(len(response.context["customers"]), 5)

Tillhandahållna testfallsklasserLink to this heading

Vanliga Python-enhetstestklasser utökar en basklass av unittest.TestCase. Django tillhandahåller några tillägg till denna basklass:

Hierarki av Djangos enhetstestklasser (TestCase-underklasser)

Hierarki av klasser för enhetstestning av DjangoLink to this image

Du kan konvertera en normal unittest.TestCase till någon av underklasserna: ändra basklassen för ditt test från unittest.TestCase till underklassen. Alla Pythons standardfunktioner för enhetstester kommer att finnas tillgängliga, och de kommer att kompletteras med några användbara tillägg som beskrivs i varje avsnitt nedan.

SimpleTestCaseLink to this heading

class SimpleTestCaseLink to this definition

En subklass av unittest.TestCase som lägger till denna funktionalitet:

Om dina tester gör några databasfrågor, använd underklasserna TransactionTestCase eller TestCase.

SimpleTestCase.databasesLink to this definition

SimpleTestCase tillåter inte databasfrågor som standard. Detta hjälper till att undvika att skriva frågor som påverkar andra tester eftersom varje SimpleTestCase-test inte körs i en transaktion. Om du inte är orolig för det här problemet kan du inaktivera det här beteendet genom att ställa in klassattributet databases till '__all__' på din testklass.

TransactionTestCaseLink to this heading

class TransactionTestCaseLink to this definition

TransactionTestCase ärver från SimpleTestCase för att lägga till några databasspecifika funktioner:

Django’s TestCase class is a more commonly used subclass of TransactionTestCase that makes use of database transaction facilities to speed up the process of resetting the database to a known state at the end of each test. A consequence of this, however, is that some database behaviors cannot be tested within a Django TestCase class. For instance, you cannot test that a block of code is executing within a transaction, as is required when using select_for_update(). In those cases, you should use TransactionTestCase.

TransactionTestCase och TestCase är identiska med undantag för det sätt på vilket databasen återställs till ett känt tillstånd och möjligheten för testkoden att testa effekterna av commit och rollback:

  • Ett TransactionTestCase återställer databasen efter testkörningen genom att trunkera alla tabeller. Ett TransactionTestCase kan anropa commit och rollback och observera effekterna av dessa anrop på databasen.

  • Ett TestCase trunkerar däremot inte tabeller efter ett test. Istället innesluts testkoden i en databastransaktion som rullas tillbaka i slutet av testet. Detta garanterar att rollback i slutet av testet återställer databasen till dess ursprungliga tillstånd.

TestCaseLink to this heading

class TestCaseLink to this definition

Detta är den vanligaste klassen att använda för att skriva tester i Django. Den ärver från TransactionTestCase (och i förlängningen SimpleTestCase). Om din Django-applikation inte använder en databas, använd SimpleTestCase.

Klassen:

  • Omsluter testerna i två nästlade atomic()-block: ett för hela klassen och ett för varje test. Därför, om du vill testa något specifikt databas transaktionsbeteende, använd TransactionTestCase.

  • Kontrollerar uppskjutbara databasbegränsningar i slutet av varje test.

Det ger också en ytterligare metod:

classmethod TestCase.setUpTestData()Link to this definition

Det atomiska block på klassnivå som beskrivs ovan gör det möjligt att skapa initialdata på klassnivå, en gång för hela TestCase. Denna teknik möjliggör snabbare tester jämfört med att använda setUp().

Till exempel:

Code
from django.test import TestCase


class MyTests(TestCase):
    @classmethod
    def setUpTestData(cls):
        # Set up data for the whole TestCase
        cls.foo = Foo.objects.create(bar="Test")
        ...

    def test1(self):
        # Some test using self.foo
        ...

    def test2(self):
        # Some other test using self.foo
        ...

Observera att om testerna körs på en databas utan transaktionsstöd (t.ex. MySQL med MyISAM-motorn) kommer setUpTestData() att anropas före varje test, vilket upphäver hastighetsfördelarna.

Objects assigned to class attributes in setUpTestData() must support creating deep copies with copy.deepcopy() in order to isolate them from alterations performed by each test methods.

classmethod TestCase.captureOnCommitCallbacks(using=DEFAULT_DB_ALIAS, execute=False)Link to this definition

Returnerar en kontexthanterare som fångar upp transaction.on_commit() callbacks för den angivna databasanslutningen. Den returnerar en lista som innehåller, vid avslutning av kontexten, de fångade återuppringningsfunktionerna. Från den här listan kan du göra påståenden om återuppringningarna eller anropa dem för att åberopa deras sidoeffekter, vilket emulerar en commit.

using är aliaset för den databasanslutning för vilken återuppringningar ska registreras.

Om execute är True kommer alla callbacks att anropas när kontexthanteraren avslutas, om inget undantag inträffade. Detta emulerar en commit efter det omslutna kodblocket.

Till exempel:

Code
from django.core import mail
from django.test import TestCase


class ContactTests(TestCase):
    def test_post(self):
        with self.captureOnCommitCallbacks(execute=True) as callbacks:
            response = self.client.post(
                "/contact/",
                {"message": "I like your site"},
            )

        self.assertEqual(response.status_code, 200)
        self.assertEqual(len(callbacks), 1)
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(mail.outbox[0].subject, "Contact Form")
        self.assertEqual(mail.outbox[0].body, "I like your site")

LiveServerTestCaseLink to this heading

class LiveServerTestCaseLink to this definition

LiveServerTestCase gör i princip samma sak som TransactionTestCase med en extra funktion: den startar en live Django-server i bakgrunden vid installationen och stänger av den vid nedmonteringen. Detta gör det möjligt att använda andra automatiserade testklienter än Django dummy client som till exempel Selenium-klienten, för att utföra en serie funktionella tester i en webbläsare och simulera en riktig användares handlingar.

Live-servern lyssnar på localhost och binder till port 0 som använder en fri port som tilldelas av operativsystemet. Serverns URL kan nås med self.live_server_url under testerna.

För att visa hur man använder LiveServerTestCase, låt oss skriva ett Selenium-test. Först och främst måste du installera paketet selenium:

Linux / macOS

Shell
$ python -m pip install "selenium >= 4.23.0"

Windows

Windows
...\> py -m pip install "selenium >= 4.23.0"

Lägg sedan till ett LiveServerTestCase-baserat test i din apps testmodul (till exempel: myapp/tests.py). I det här exemplet antar vi att du använder staticfiles-appen och vill ha statiska filer serverade under körningen av dina tester liknande det vi får vid utvecklingstid med DEBUG=True, dvs. utan att behöva samla in dem med collectstatic. Vi kommer att använda StaticLiveServerTestCase subklassen som tillhandahåller den funktionaliteten. Ersätt den med django.test.LiveServerTestCase om du inte behöver det.

Koden för detta test kan se ut på följande sätt:

Code
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.webdriver import WebDriver


class MySeleniumTests(StaticLiveServerTestCase):
    fixtures = ["user-data.json"]

    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.selenium = WebDriver()
        cls.selenium.implicitly_wait(10)

    @classmethod
    def tearDownClass(cls):
        cls.selenium.quit()
        super().tearDownClass()

    def test_login(self):
        self.selenium.get(f"{self.live_server_url}/login/")
        username_input = self.selenium.find_element(By.NAME, "username")
        username_input.send_keys("myuser")
        password_input = self.selenium.find_element(By.NAME, "password")
        password_input.send_keys("secret")
        self.selenium.find_element(By.XPATH, '//input[@value="Log in"]').click()

Slutligen kan du köra testet på följande sätt:

Linux / macOS

Shell
$ ./manage.py test myapp.tests.MySeleniumTests.test_login

Windows

Windows
...\> manage.py test myapp.tests.MySeleniumTests.test_login

Detta exempel kommer automatiskt att öppna Firefox och sedan gå till inloggningssidan, ange inloggningsuppgifterna och trycka på knappen ”Logga in”. Selenium erbjuder andra drivrutiner om du inte har Firefox installerat eller vill använda en annan webbläsare. Exemplet ovan är bara en liten bråkdel av vad Selenium-klienten kan göra; kolla in full reference för mer information.

Testfall funktionerLink to this heading

Standard testklientLink to this heading

SimpleTestCase.clientLink to this definition
SimpleTestCase.async_clientLink to this definition

Every django.test.*TestCase instance has access to Django’s synchronous and asynchronous test clients as self.client and self.async_client, respectively. Both clients are recreated for each test, so you don’t have to worry about state (such as cookies) carrying over from one test to another.

For example, rather than instantiating a Client in each test:

Code
import unittest
from django.test import Client


class SimpleTest(unittest.TestCase):
    def test_details(self):
        client = Client()
        response = client.get("/customer/details/")
        self.assertEqual(response.status_code, 200)

    def test_index(self):
        client = Client()
        response = client.get("/customer/index/")
        self.assertEqual(response.status_code, 200)

…kan du hänvisa till self.client, så här:

Code
from django.test import TestCase


class SimpleTest(TestCase):
    def test_details(self):
        response = self.client.get("/customer/details/")
        self.assertEqual(response.status_code, 200)

    def test_index(self):
        response = self.client.get("/customer/index/")
        self.assertEqual(response.status_code, 200)

Anpassning av testklientenLink to this heading

SimpleTestCase.client_classLink to this definition
SimpleTestCase.async_client_classLink to this definition

If you want to use a different Client or AsyncClient class (for example, a subclass with customized behavior), use the client_class or async_client_class class attributes.

For example, to customize the synchronous test client:

Code
from django.test import Client, TestCase


class MyTestClient(Client):
    # Specialized methods for your environment
    ...


class MyTest(TestCase):
    client_class = MyTestClient

    def test_my_stuff(self):
        # Here self.client is an instance of MyTestClient...
        call_some_test_code()

The same pattern applies to the asynchronous test client by subclassing AsyncClient and setting async_client_class.

Lastning av fixturLink to this heading

TransactionTestCase.fixturesLink to this definition

En testfallsklass för en databasbaserad webbplats är inte till någon större nytta om det inte finns några data i databasen. Tester är mer läsbara och det är mer underhållbart att skapa objekt med hjälp av ORM, till exempel i TestCase.setUpTestData(), men du kan också använda fixtures.

En fixtur är en samling data som Django vet hur man importerar till en databas. Om din webbplats till exempel har användarkonton kan du skapa en fixtur med falska användarkonton för att fylla på din databas under tester.

Det enklaste sättet att skapa en fixtur är att använda kommandot manage.py dumpdata. Detta förutsätter att du redan har en del data i din databas. Se dumpdata documentation för mer information.

När du har skapat en fixtur och placerat den i en fixtures katalog i en av dina INSTALLED_APPS, kan du använda den i dina enhetstester genom att ange ett fixtures klassattribut på din django.test.TestCase subclass:

Code
from django.test import TestCase
from myapp.models import Animal


class AnimalTestCase(TestCase):
    fixtures = ["mammals.json", "birds"]

    def setUp(self):
        # Test definitions as before.
        call_setup_methods()

    def test_fluffy_animals(self):
        # A test that uses the fixtures.
        call_some_test_code()

Det här är vad som kommer att hända i detalj:

  • Under setUpClass() installeras alla namngivna fixturer. I det här exemplet kommer Django att installera alla JSON-fixturer med namnet mammals, följt av alla fixturer med namnet birds. Se ämnet Fixturer för mer information om hur man definierar och installerar fixturer.

För de flesta enhetstester som använder TestCase behöver Django inte göra något annat, eftersom transaktioner används för att rensa databasen efter varje test av prestandaskäl. Men för TransactionTestCase kommer följande åtgärder att äga rum:

  • I slutet av varje test kommer Django att spola databasen, vilket återställer databasen till det tillstånd den befann sig i direkt efter att migrate anropades.

  • För varje efterföljande test kommer fixturerna att laddas om innan setUp() körs.

I vilket fall som helst kan du vara säker på att resultatet av ett test inte kommer att påverkas av ett annat test eller av ordningen på testgenomförandet.

Som standard laddas fixturer endast in i databasen default. Om du använder flera databaser och anger TransactionTestCase.databases kommer fixturer att laddas i alla angivna databaser.

URLconf-konfigurationLink to this heading

Om din applikation innehåller vyer kanske du vill inkludera tester som använder testklienten för att aktivera dessa vyer. Det står dock en slutanvändare fritt att distribuera vyerna i din applikation till vilken URL som helst. Detta innebär att dina tester inte kan förlita sig på att dina vyer kommer att finnas tillgängliga på en viss URL. Dekorera din testklass eller testmetod med @override_settings(ROOT_URLCONF=...) för URLconf-konfiguration.

Stöd för flera databaserLink to this heading

TransactionTestCase.databasesLink to this definition

Django skapar en testdatabas som motsvarar varje databas som definieras i DATABASER-definitionen i dina inställningar och som minst ett test hänvisar till via databaser.

En stor del av den tid det tar att köra ett Django TestCase förbrukas dock av anropet till flush som säkerställer att du har en ren databas i slutet av varje testkörning. Om du har flera databaser krävs flera spolningar (en för varje databas), vilket kan vara en tidskrävande aktivitet - särskilt om dina tester inte behöver testa aktivitet i flera databaser.

Som en optimering spolar Django bara databasen default i slutet av varje testkörning. Om din installation innehåller flera databaser och du har ett test som kräver att alla databaser är rena, kan du använda attributet databaser på testsviten för att begära att extra databaser spolas.

Till exempel:

Code
class TestMyViews(TransactionTestCase):
    databases = {"default", "other"}

    def test_index_page_view(self):
        call_some_test_code()

Denna testfallsklass kommer att rensa testdatabaserna default och other efter att ha kört test_index_page_view. Du kan också använda '__all__' för att ange att alla testdatabaser måste rensas.

Flaggan databases styr också vilka databaser som TransactionTestCase.fixtures laddas in i. Som standard laddas fixturerna endast in i databasen default.

Frågor mot databaser som inte finns i databaser kommer att ge assertionfel för att förhindra att tillstånd läcker mellan tester.

TestCase.databasesLink to this definition

Som standard kommer endast standard-databasen att omslutas av en transaktion under exekveringen av ett TestCase och försök att fråga andra databaser kommer att resultera i assertionfel för att förhindra att tillstånd läcker mellan tester.

Använd klassattributet databases på testklassen för att begära transaktionsomslag mot databaser som inte är standard.

Till exempel:

Code
class OtherDBTests(TestCase):
    databases = {"other"}

    def test_other_db_query(self): ...

Detta test tillåter endast frågor mot databasen other. Precis som för SimpleTestCase.databases och TransactionTestCase.databases kan konstanten '__all__' användas för att ange att testet ska tillåta frågor till alla databaser.

Åsidosätta inställningarLink to this heading

SimpleTestCase.settings()Link to this definition

For testing purposes it’s often useful to change a setting temporarily and revert to the original value after running the testing code. For this use case Django provides a standard context manager called settings(), which can be used like this:

Code
from django.test import TestCase


class LoginTestCase(TestCase):
    def test_login(self):
        # First check for the default behavior
        response = self.client.get("/sekrit/")
        self.assertRedirects(response, "/accounts/login/?next=/sekrit/")

        # Then override the LOGIN_URL setting
        with self.settings(LOGIN_URL="/other/login/"):
            response = self.client.get("/sekrit/")
            self.assertRedirects(response, "/other/login/?next=/sekrit/")

Detta exempel åsidosätter inställningen LOGIN_URL för koden i with-blocket och återställer dess värde till det tidigare tillståndet efteråt.

SimpleTestCase.modify_settings()Link to this definition

Det kan vara krångligt att omdefiniera inställningar som innehåller en lista med värden. I praktiken är det ofta tillräckligt att lägga till eller ta bort värden. Django tillhandahåller kontexthanteraren modify_settings() för enklare ändringar av inställningar:

Code
from django.test import TestCase


class MiddlewareTestCase(TestCase):
    def test_cache_middleware(self):
        with self.modify_settings(
            MIDDLEWARE={
                "append": "django.middleware.cache.FetchFromCacheMiddleware",
                "prepend": "django.middleware.cache.UpdateCacheMiddleware",
                "remove": [
                    "django.contrib.sessions.middleware.SessionMiddleware",
                    "django.contrib.auth.middleware.AuthenticationMiddleware",
                    "django.contrib.messages.middleware.MessageMiddleware",
                ],
            }
        ):
            response = self.client.get("/")
            # ...

För varje åtgärd kan du ange antingen en lista med värden eller en sträng. När värdet redan finns i listan har append och prepend ingen effekt; det har inte heller remove när värdet inte finns.

override_settings(**kwargs)Link to this definition

In case you want to override a setting for a test method, Django provides the override_settings() decorator:

Code
from django.test import TestCase, override_settings


class LoginTestCase(TestCase):
    @override_settings(LOGIN_URL="/other/login/")
    def test_login(self):
        response = self.client.get("/sekrit/")
        self.assertRedirects(response, "/other/login/?next=/sekrit/")

Dekoratorn kan också tillämpas på TestCase-klasser:

Code
from django.test import TestCase, override_settings


@override_settings(LOGIN_URL="/other/login/")
class LoginTestCase(TestCase):
    def test_login(self):
        response = self.client.get("/sekrit/")
        self.assertRedirects(response, "/other/login/?next=/sekrit/")
modify_settings(*args, **kwargs)Link to this definition

På samma sätt tillhandahåller Django dekoratorn modify_settings():

Code
from django.test import TestCase, modify_settings


class MiddlewareTestCase(TestCase):
    @modify_settings(
        MIDDLEWARE={
            "append": "django.middleware.cache.FetchFromCacheMiddleware",
            "prepend": "django.middleware.cache.UpdateCacheMiddleware",
        }
    )
    def test_cache_middleware(self):
        response = self.client.get("/")
        # ...

Dekoratorn kan också tillämpas på testfallsklasser:

Code
from django.test import TestCase, modify_settings


@modify_settings(
    MIDDLEWARE={
        "append": "django.middleware.cache.FetchFromCacheMiddleware",
        "prepend": "django.middleware.cache.UpdateCacheMiddleware",
    }
)
class MiddlewareTestCase(TestCase):
    def test_cache_middleware(self):
        response = self.client.get("/")
        # ...

Du kan också simulera att en inställning inte finns genom att radera den efter att inställningarna har åsidosatts, så här:

Code
@override_settings()
def test_something(self):
    del settings.LOGIN_URL
    ...

När du åsidosätter inställningar måste du se till att hantera de fall där din appkod använder en cache eller liknande funktion som behåller tillståndet även om inställningen ändras. Django tillhandahåller django.test.signals.setting_changed-signalen som låter dig registrera återuppringningar för att städa upp och på annat sätt återställa tillståndet när inställningarna ändras.

Django själv använder denna signal för att återställa olika data:

Åsidosatta inställningar

Återställning av data

ANVÄNDNING_TZ, TIDSZON

Tidszon för databaser

TEMPLAT

Mall för motorer

FORM_RENDERER

Standardrenderare

SERIALISERING_MODULER

Serialisatorer cache

LOKALA_ SÖKVÄGAR, SPRÅKKOD

Standardöversättning och inlästa översättningar

STATIC_ROOT, STATIC_URL, LAGRING

Konfiguration av lagringsutrymmen

Isolera apparLink to this heading

utils.isolate_apps(*app_labels, attr_name=None, kwarg_name=None)Link to this definition

Registrerar de modeller som definieras i en omsluten kontext i sitt eget isolerade apps-register. Denna funktion är användbar när du skapar modellklasser för tester, eftersom klasserna kommer att raderas rent efteråt och det inte finns någon risk för namnkollisioner.

De appetiketter som det isolerade registret ska innehålla måste skickas som enskilda argument. Du kan använda isolate_apps() som en dekorator eller en kontexthanterare. Till exempel:

Code
from django.db import models
from django.test import SimpleTestCase
from django.test.utils import isolate_apps


class MyModelTests(SimpleTestCase):
    @isolate_apps("app_label")
    def test_model_definition(self):
        class TestModel(models.Model):
            pass

        ...

… eller:

Code
with isolate_apps("app_label"):

    class TestModel(models.Model):
        pass

    ...

Dekoratorformen kan också tillämpas på klasser.

Två valfria nyckelordsargument kan anges:

  • attr_name: attribut som tilldelas det isolerade registret om det används som en klassdekorator.

  • kwarg_name: nyckelordsargument som skickar det isolerade registret om det används som en funktionsdekorator.

Den tillfälliga instansen Apps som används för att isolera modellregistreringen kan hämtas som ett attribut när den används som en klassdekorator genom att använda parametern attr_name:

Code
@isolate_apps("app_label", attr_name="apps")
class TestModelDefinition(SimpleTestCase):
    def test_model_definition(self):
        class TestModel(models.Model):
            pass

        self.assertIs(self.apps.get_model("app_label", "TestModel"), TestModel)

… eller alternativt som ett argument på testmetoden när den används som en metoddekorator genom att använda parametern kwarg_name:

Code
class TestModelDefinition(SimpleTestCase):
    @isolate_apps("app_label", kwarg_name="apps")
    def test_model_definition(self, apps):
        class TestModel(models.Model):
            pass

        self.assertIs(apps.get_model("app_label", "TestModel"), TestModel)

Tömning av testboxenLink to this heading

Om du använder någon av Djangos anpassade TestCase-klasser kommer testlöparen att rensa innehållet i test-e-postens utkorg i början av varje testfall.

För mer information om e-posttjänster under tester, se E-posttjänster nedan.

PåståendenLink to this heading

Precis som Pythons normala klass unittest.TestCase implementerar assertion-metoder som assertTrue() och assertEqual(), tillhandahåller Djangos anpassade klass TestCase ett antal anpassade assertion-metoder som är användbara för att testa webbapplikationer:

De felmeddelanden som ges av de flesta av dessa assertion-metoder kan anpassas med argumentet msg_prefix. Denna sträng kommer att prefixeras till alla felmeddelanden som genereras av påståendet. Detta gör att du kan ge ytterligare information som kan hjälpa dig att identifiera platsen för och orsaken till ett fel i din testsvit.

SimpleTestCase.assertRaisesMessage(expected_exception, expected_message, callable, *args, **kwargs)Link to this definition
SimpleTestCase.assertRaisesMessage(expected_exception, expected_message)

Säger att exekvering av callable ger upphov till expected_exception och att expected_message finns i undantagets meddelande. Alla andra resultat rapporteras som ett misslyckande. Det är en enklare version av unittest.TestCase.assertRaisesRegex() med skillnaden att expected_message inte behandlas som ett reguljärt uttryck.

Om endast parametrarna expected_exception och expected_message anges, returneras en kontexthanterare så att den kod som testas kan skrivas inline i stället för som en funktion:

Code
with self.assertRaisesMessage(ValueError, "invalid literal for int()"):
    int("a")
SimpleTestCase.assertWarnsMessage(expected_warning, expected_message, callable, *args, **kwargs)Link to this definition
SimpleTestCase.assertWarnsMessage(expected_warning, expected_message)

Analogt med SimpleTestCase.assertRaisesMessage() men för assertWarnsRegex() istället för assertRaisesRegex().

SimpleTestCase.assertFieldOutput(fieldclass, valid, invalid, field_args=None, field_kwargs=None, empty_value='')Link to this definition

Försäkrar att ett formulärfält beter sig korrekt med olika inmatningar.

Parametrar:
  • fieldclass – klassen för det fält som ska testas.

  • valid – en ordlista som mappar giltiga indata till deras förväntade rensade värden.

  • invalid – en ordlista som kopplar ogiltiga indata till ett eller flera felmeddelanden.

  • field_args – de args som skickas för att instansiera fältet.

  • field_kwargs – de kwargs som skickas för att instansiera fältet.

  • empty_value – den förväntade rena utdata för indata i empty_values.

Följande kod testar till exempel att en EmailField accepterar a@a.com som en giltig e-postadress, men avvisar aaa med ett rimligt felmeddelande:

Code
self.assertFieldOutput(
    EmailField, {"a@a.com": "a@a.com"}, {"aaa": ["Enter a valid email address."]}
)
SimpleTestCase.assertFormError(form, field, errors, msg_prefix='')Link to this definition

Säger att ett fält i ett formulär ger upphov till den angivna listan med fel.

form är en Form instans. Formuläret måste vara bundet men inte nödvändigtvis validerat (assertFormError() kommer automatiskt att anropa full_clean() på formuläret).

field är namnet på det fält i formuläret som ska kontrolleras. För att kontrollera formulärets icke-fältfel, använd field=None.

errors är en lista med alla felsträngar som fältet förväntas ha. Du kan också skicka en enda felsträng om du bara förväntar dig ett fel, vilket innebär att errors='error message' är detsamma som errors=['error message'].

SimpleTestCase.assertFormSetError(formset, form_index, field, errors, msg_prefix='')Link to this definition

Säger att formset ger upphov till den angivna listan med fel när det renderas.

formset är en instans av FormSet. Formsetet måste vara bundet men inte nödvändigtvis validerat (assertFormSetError() anropar automatiskt full_clean() på formsetet).

form_index är numret på formuläret i FormSet (med början från 0). Använd form_index=None för att kontrollera formuläruppsättningens icke-formulärfel, dvs. de fel som du får när du anropar formset.non_form_errors(). I så fall måste du också använda field=None.

field och errors har samma betydelse som parametrarna till assertFormError().

SimpleTestCase.assertContains(response, text, count=None, status_code=200, msg_prefix='', html=False)Link to this definition

Asserts that an HttpResponse produced the given status_code and that text appears in its content. If count is provided, text must occur exactly count times in the response.

Sätt html till True för att hantera text som HTML. Jämförelsen med svarsinnehållet kommer att baseras på HTML-semantik i stället för likhet tecken för tecken. Whitespace ignoreras i de flesta fall, attributordning är inte signifikant. Se assertHTMLEqual() för mer information.

SimpleTestCase.assertNotContains(response, text, status_code=200, msg_prefix='', html=False)Link to this definition

Asserts that an HttpResponse produced the given status_code and that text does not appear in its content.

Sätt html till True för att hantera text som HTML. Jämförelsen med svarsinnehållet kommer att baseras på HTML-semantik i stället för likhet tecken för tecken. Whitespace ignoreras i de flesta fall, attributordning är inte signifikant. Se assertHTMLEqual() för mer information.

SimpleTestCase.assertTemplateUsed(response, template_name, msg_prefix='', count=None)Link to this definition

Bekräftar att mallen med det angivna namnet användes vid rendering av svaret.

response must be a Response instance returned by the test client.

template_name bör vara en sträng som till exempel 'admin/index.html'.

Argumentet count är ett heltal som anger hur många gånger mallen ska återges. Standard är None, vilket innebär att mallen ska återges en eller flera gånger.

Du kan använda detta som en kontexthanterare, så här:

Code
with self.assertTemplateUsed("index.html"):
    render_to_string("index.html")
with self.assertTemplateUsed(template_name="index.html"):
    render_to_string("index.html")
SimpleTestCase.assertTemplateNotUsed(response, template_name, msg_prefix='')Link to this definition

Bekräftar att mallen med det angivna namnet inte användes vid rendering av svaret.

Du kan använda detta som en kontexthanterare på samma sätt som assertTemplateUsed().

SimpleTestCase.assertURLEqual(url1, url2, msg_prefix='')Link to this definition

Påstår att två webbadresser är desamma och ignorerar ordningen på parametrarna i frågesträngen, utom för parametrar med samma namn. Till exempel är /path/?x=1&y=2 lika med /path/?y=2&x=1, men /path/?a=1&a=2 är inte lika med /path/?a=2&a=1.

SimpleTestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prefix='', fetch_redirect_response=True)Link to this definition

Asserts that the HttpResponse returned a response with a redirect status (based on its status_code), redirected to expected_url (including any GET data), and that the final response was received with target_status_code.

Om din begäran använde argumentet follow kommer expected_url och target_status_code att vara webbadressen och statuskoden för den sista punkten i omdirigeringskedjan.

Om fetch_redirect_response är False kommer den slutliga sidan inte att laddas. Eftersom testklienten inte kan hämta externa webbadresser är detta särskilt användbart om expected_url inte är en del av din Django-app.

Schema hanteras korrekt när jämförelser görs mellan två webbadresser. Om det inte finns något schema angivet på den plats dit vi omdirigeras används den ursprungliga begärans schema. Om det finns, är det schemat i expected_url som används för att göra jämförelser.

SimpleTestCase.assertHTMLEqual(html1, html2, msg=None)Link to this definition

Påstår att strängarna html1 och html2 är lika. Jämförelsen är baserad på HTML-semantik. Jämförelsen tar hänsyn till följande saker:

  • Mellanslag före och efter HTML-taggar ignoreras.

  • Alla typer av blanksteg betraktas som likvärdiga.

  • Alla öppna taggar stängs implicit, t.ex. när en omgivande tagg stängs eller när HTML-dokumentet avslutas.

  • Tomma taggar är likvärdiga med deras självstängande version.

  • Ordningsföljden på attributen i ett HTML-element är inte viktig.

  • Booleska attribut (t.ex. checked) utan argument är lika med attribut som har samma namn och värde (se exemplen).

  • Text-, tecken- och entitetsreferenser som hänvisar till samma tecken är likvärdiga.

Följande exempel är giltiga tester och ger inte upphov till några AssertionError:

Code
self.assertHTMLEqual(
    "<p>Hello <b>&#x27;world&#x27;!</p>",
    """<p>
        Hello   <b>&#39;world&#39;! </b>
    </p>""",
)
self.assertHTMLEqual(
    '<input type="checkbox" checked="checked" id="id_accept_terms" />',
    '<input id="id_accept_terms" type="checkbox" checked>',
)

html1 och html2 måste innehålla HTML. Ett AssertionError kommer att uppstå om en av dem inte kan tolkas.

Utdata i händelse av fel kan anpassas med argumentet msg.

SimpleTestCase.assertHTMLNotEqual(html1, html2, msg=None)Link to this definition

Påstår att strängarna html1 och html2 är inte lika. Jämförelsen baseras på HTML-semantik. Se assertHTMLEqual() för detaljer.

html1 och html2 måste innehålla HTML. Ett AssertionError kommer att uppstå om en av dem inte kan tolkas.

Utdata i händelse av fel kan anpassas med argumentet msg.

SimpleTestCase.assertXMLEqual(xml1, xml2, msg=None)Link to this definition

Påstår att strängarna xml1 och xml2 är lika. Jämförelsen baseras på XML-semantik. På samma sätt som assertHTMLEqual(), görs jämförelsen på parsat innehåll, vilket innebär att endast semantiska skillnader beaktas, inte syntaxskillnader. När ogiltig XML skickas i någon parameter, uppstår alltid ett AssertionError, även om båda strängarna är identiska.

XML-deklaration, dokumenttyp, bearbetningsinstruktioner och kommentarer ignoreras. Endast rotelementet och dess underordnade element jämförs.

Utdata i händelse av fel kan anpassas med argumentet msg.

SimpleTestCase.assertXMLNotEqual(xml1, xml2, msg=None)Link to this definition

Påstår att strängarna xml1 och xml2 är inte lika. Jämförelsen är baserad på XML-semantik. Se assertXMLEqual() för detaljer.

Utdata i händelse av fel kan anpassas med argumentet msg.

SimpleTestCase.assertInHTML(needle, haystack, count=None, msg_prefix='')Link to this definition

Påstår att HTML-fragmentet needle ingår i haystack en gång.

Om heltalsargumentet count anges, kommer dessutom antalet förekomster av nålar att kontrolleras noggrant.

I de flesta fall ignoreras blanksteg och attributordningen är inte signifikant. Se assertHTMLEqual() för mer information.

SimpleTestCase.assertNotInHTML(needle, haystack, msg_prefix='')Link to this definition

Påstår att HTML-fragmentet needle inte ingår i haystack.

I de flesta fall ignoreras blanksteg och attributordningen är inte signifikant. Se assertHTMLEqual() för mer information.

SimpleTestCase.assertJSONEqual(raw, expected_data, msg=None)Link to this definition

Påstår att JSON-fragmenten raw och expected_data är lika. Vanliga JSON-regler för icke-signifikanta blanksteg gäller eftersom tungvikten är delegerad till json-biblioteket.

Utdata i händelse av fel kan anpassas med argumentet msg.

SimpleTestCase.assertJSONNotEqual(raw, expected_data, msg=None)Link to this definition

Säger att JSON-fragmenten raw och expected_data inte är lika. Se assertJSONEqual() för ytterligare detaljer.

Utdata i händelse av fel kan anpassas med argumentet msg.

TransactionTestCase.assertQuerySetEqual(qs, values, transform=None, ordered=True, msg=None)Link to this definition

Säger att en frågeuppsättning qs matchar en viss iterabel av värden values.

Om transform anges, jämförs values med en lista som framställs genom att transform tillämpas på varje medlem i qs.

Som standard är jämförelsen också beroende av ordning. Om qs inte tillhandahåller en implicit ordning kan du ställa in parametern ordered till False, vilket gör jämförelsen till en collections.Counter jämförelse. Om ordningen är odefinierad (om den givna qs inte är ordnad och jämförelsen är mot mer än ett ordnat värde), kommer ett ValueError att uppstå.

Utdata i händelse av fel kan anpassas med argumentet msg.

TransactionTestCase.assertNumQueries(num, func, *args, **kwargs)Link to this definition

Säger att när func anropas med *args och **kwargs så körs num databasfrågor.

Om en "using"-nyckel finns i kwargs används den som databasalias för att kontrollera antalet frågor:

Code
self.assertNumQueries(7, my_function, using="non_default_db")

Om du vill anropa en funktion med en using parameter kan du göra det genom att omsluta anropet med en lambda för att lägga till en extra parameter:

Code
self.assertNumQueries(7, lambda: my_function(using=7))

Du kan också använda detta som en kontexthanterare:

Code
with self.assertNumQueries(2):
    Person.objects.create(name="Aaron")
    Person.objects.create(name="Daniel")

Taggning av testerLink to this heading

Du kan märka dina tester så att du enkelt kan köra en viss delmängd. Du kan till exempel märka snabba eller långsamma tester:

Code
from django.test import tag


class SampleTestCase(TestCase):
    @tag("fast")
    def test_fast(self): ...

    @tag("slow")
    def test_slow(self): ...

    @tag("slow", "core")
    def test_slow_but_core(self): ...

Du kan också tagga en testfallsklass:

Code
@tag("slow", "core")
class SampleTestCase(TestCase): ...

Underklasser ärver taggar från överklasser och metoder ärver taggar från sin klass. Givet:

Code
@tag("foo")
class SampleTestCaseChild(SampleTestCase):
    @tag("bar")
    def test(self): ...

SampleTestCaseChild.test kommer att märkas med 'slow', 'core', 'bar' och 'foo'.

Sedan kan du välja vilka tester som ska köras. Till exempel om du bara vill köra snabba tester:

Linux / macOS

Shell
$ ./manage.py test --tag=fast

Windows

Windows
...\> manage.py test --tag=fast

Eller för att köra snabba tester och kärntesten (även om den är långsam):

Linux / macOS

Shell
$ ./manage.py test --tag=fast --tag=core

Windows

Windows
...\> manage.py test --tag=fast --tag=core

Du kan också utesluta tester med hjälp av taggar. För att köra kärntester om de inte är långsamma:

Linux / macOS

Shell
$ ./manage.py test --tag=core --exclude-tag=slow

Windows

Windows
...\> manage.py test --tag=core --exclude-tag=slow

test --exclude-tag har företräde framför test --tag, så om ett test har två taggar och du väljer en av dem och utesluter den andra, kommer testet inte att köras.

Testning av asynkron kodLink to this heading

Om du bara vill testa utdata från dina asynkrona vyer kommer standardtestklienten att köra dem i sin egen asynkrona loop utan något extra arbete från din sida.

Men om du vill skriva helt asynkrona tester för ett Django-projekt måste du ta hänsyn till flera saker.

För det första måste dina tester vara async def-metoder på testklassen (för att ge dem ett asynkront sammanhang). Django kommer automatiskt att upptäcka alla async def-tester och linda in dem så att de körs i sin egen händelseslinga.

Om du testar från en asynkron funktion måste du också använda den asynkrona testklienten. Detta är tillgängligt som django.test.AsyncClient, eller som self.async_client på alla tester.

class AsyncClient(enforce_csrf_checks=False, raise_request_exception=True, *, headers=None, query_params=None, **defaults)Link to this definition

AsyncClient har samma metoder och signaturer som den synkrona (normala) testklienten, med följande undantag:

  • Vid initialiseringen läggs godtyckliga nyckelordsargument i defaults till direkt i ASGI-scopet.

  • Headers som skickas som extra nyckelordsargument bör inte ha prefixet HTTP_ som krävs av den synkrona klienten (se Client.get()). Till exempel, så här ställer du in en HTTP Accept header:

    Python console
    >>> c = AsyncClient()
    >>> c.get("/customers/details/", {"name": "fred", "age": 7}, ACCEPT="application/json")
    

Med hjälp av AsyncClient måste alla metoder som gör en begäran väntas:

Code
async def test_my_thing(self):
    response = await self.async_client.get("/some-url/")
    self.assertEqual(response.status_code, 200)

Den asynkrona klienten kan också anropa synkrona vyer; den körs genom Djangos asynkrona sökväg, som stöder båda. Varje vy som anropas via AsyncClient kommer att få ett ASGIRequest-objekt för sin request snarare än WSGIRequest som den normala klienten skapar.

E-posttjänsterLink to this heading

If any of your code sends email using Django’s email functionality, you probably don’t want to send email each time you run a test that exercises that code. For this reason, Django’s test runner automatically redirects all Django-sent email to an in-memory outbox. This lets you test every aspect of sending email – from the number of messages sent to the contents of each message – without actually sending the messages.

The test runner accomplishes this by transparently replacing the BACKEND for each configured MAILERS alias with the 'locmem' memory email backend. (Don’t worry – this has no effect on any other email senders outside of Django, such as your machine’s mail server, if you’re running one.)

django.core.mail.outboxLink to this definition

During test running, each outgoing email is saved in django.core.mail.outbox. This is a list of all EmailMessage instances that have been sent. The outbox attribute is a special attribute that is created only when the locmem email backend is used. It doesn’t normally exist as part of the django.core.mail module and you can’t import it directly. The code below shows how to access this attribute correctly.

Här är ett exempel på ett test som undersöker django.core.mail.outbox för längd och innehåll:

Code
from django.core import mail
from django.test import TestCase


class EmailTest(TestCase):
    def test_send_email(self):
        # Send message.
        mail.send_mail(
            "Subject here",
            "Here is the message.",
            "from@example.com",
            ["to@example.com"],
        )

        # Test that one message has been sent.
        self.assertEqual(len(mail.outbox), 1)

        # Verify that the subject of the first message is correct.
        self.assertEqual(mail.outbox[0].subject, "Subject here")

        # Verify the message was sent with the "default" mailer.
        self.assertEqual(mail.outbox[0].sent_using, "default")

Som nämnts tidigare, töms testutkorgen i början av varje test i ett Django *TestCase. För att tömma utkorgen manuellt, tilldela den tomma listan till mail.outbox:

Code
from django.core import mail

# Empty the test outbox
mail.outbox = []

Kommandon för hanteringLink to this heading

Hanteringskommandon kan testas med funktionen call_command(). Utdata kan omdirigeras till en StringIO-instans:

Code
from io import StringIO
from django.core.management import call_command
from django.test import TestCase


class ClosepollTest(TestCase):
    def test_command_output(self):
        out = StringIO()
        call_command("closepoll", poll_ids=[1], stdout=out)
        self.assertIn('Successfully closed poll "1"', out.getvalue())

Skippa provLink to this heading

Biblioteket unittest tillhandahåller dekoratorerna @skipIf och @skipUnless så att du kan hoppa över tester om du i förväg vet att dessa tester kommer att misslyckas under vissa förutsättningar.

Om ditt test till exempel kräver ett visst valfritt bibliotek för att lyckas, kan du dekorera testfallet med @skipIf. Då kommer testköraren att rapportera att testet inte kördes och varför, istället för att misslyckas med testet eller utelämna testet helt och hållet.

För att komplettera dessa testöverhoppningsbeteenden tillhandahåller Django ytterligare två skip-dekoratorer. Istället för att testa en generisk boolean, kontrollerar dessa dekoratorer databasens kapacitet och hoppar över testet om databasen inte stöder en specifik namngiven funktion.

Dekoratörerna använder en strängidentifierare för att beskriva databasfunktioner. Denna sträng motsvarar attribut i klassen för databasanslutningsfunktioner. Se django.db.backends.base.features.BaseDatabaseFeatures class för en fullständig lista över databasfunktioner som kan användas som grund för att hoppa över tester.

skipIfDBFeature(*feature_name_strings)Link to this definition

Hoppa över det dekorerade testet eller TestCase om alla de namngivna databasfunktionerna stöds.

Till exempel kommer följande test inte att utföras om databasen stöder transaktioner (t.ex. skulle det * inte * köras under PostgreSQL, men det skulle under MySQL med MyISAM-tabeller):

Code
class MyTests(TestCase):
    @skipIfDBFeature("supports_transactions")
    def test_transaction_behavior(self):
        # ... conditional test code
        pass
skipUnlessDBFeature(*feature_name_strings)Link to this definition

Hoppa över det dekorerade testet eller TestCase om någon av de namngivna databasfunktionerna inte stöds.

Till exempel kommer följande test endast att utföras om databasen stöder transaktioner (t.ex. skulle det köras under PostgreSQL, men * inte * under MySQL med MyISAM-tabeller):

Code
class MyTests(TestCase):
    @skipUnlessDBFeature("supports_transactions")
    def test_transaction_behavior(self):
        # ... conditional test code
        pass