Einführung
Dieser Tutorial beginnt dort, wo **Form Processing and Cutting Down Our Code**
aufgehört hat. Wir haben eine Weboberflächen-Umfrageanwendung gebaut und werden nun einige automatisierte Tests für sie erstellen.
💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken
Dieser Tutorial beginnt dort, wo **Form Processing and Cutting Down Our Code**
aufgehört hat. Wir haben eine Weboberflächen-Umfrageanwendung gebaut und werden nun einige automatisierte Tests für sie erstellen.
Tests sind Routinen, die die Funktionsweise Ihres Codes überprüfen.
Das Testen erfolgt auf verschiedenen Ebenen. Einige Tests können sich auf einen winzigen Detailbereich beziehen („gibt eine bestimmte Modellmethode die erwarteten Werte zurück?“), während andere die Gesamtfunktionsweise der Software untersuchen („erzeugt eine Sequenz von Benutzereingaben auf der Website das gewünschte Ergebnis?“). Dies unterscheidet sich nicht von der Art des Tests, die Sie früher in **Set Up the Database**
durchgeführt haben, indem Sie die shell
verwendet haben, um das Verhalten einer Methode zu untersuchen, oder indem Sie die Anwendung ausgeführt und Daten eingegeben haben, um zu überprüfen, wie sie sich verhält.
Was bei automatisierten Tests anders ist, ist, dass die Testarbeit vom System für Sie erledigt wird. Sie erstellen einmal eine Reihe von Tests, und wenn Sie Ihre App ändern, können Sie überprüfen, ob Ihr Code weiterhin wie ursprünglich geplant funktioniert, ohne dass Sie zeitaufwendiges manuelles Testen vornehmen müssen.
Warum sollten Sie Tests erstellen und warum gerade jetzt?
Sie mögen sich vielleicht denken, dass Sie schon genug auf dem Teller haben, indem Sie nur noch Python/Django lernen, und dass das Lernen und Tun noch eines weiteren Dings überwältigend und vielleicht sogar unnötig erscheint. Nach allem, was wir wissen, funktioniert unsere Umfrageanwendung derzeit problemlos; das Aufwand der Erstellung automatisierter Tests wird sie nicht funktionieren lassen. Wenn das Erstellen der Umfrageanwendung der letzte Schritt der Django-Programmierung ist, die Sie jemals ausführen werden, dann stimmt es, dass Sie nicht wissen müssen, wie automatisierte Tests erstellt werden. Wenn das jedoch nicht der Fall ist, ist jetzt ein ausgezeichneter Zeitpunkt, um zu lernen.
Bis zu einem gewissen Punkt wird das „Überprüfen, ob es funktioniert“ ein zufriedenstellender Test sein. In einer komplexeren Anwendung können Sie zwischen den Komponenten zahlreiche komplexe Interaktionen haben.
Eine Änderung in einer dieser Komponenten kann unerwartete Auswirkungen auf das Verhalten der Anwendung haben. Das Überprüfen, ob es weiterhin „funktioniert“, kann bedeuten, dass Sie durch die Funktionalität Ihres Codes mit zwanzig verschiedenen Variationen Ihrer Testdaten laufen, um sicherzustellen, dass Sie nichts kaputt gemacht haben – kein guter Zeitverbrauch.
Dies trifft besonders zu, wenn automatisierte Tests dies für Sie in wenigen Sekunden erledigen können. Wenn etwas schiefgeht, helfen Ihnen Tests auch bei der Identifizierung des Codes, der das unerwartete Verhalten verursacht.
Manchmal kann es sich anfühlen, als wäre es eine Last, sich von Ihrer produktiven, kreativen Programmierarbeit zu lösen, um der langweiligen und unaufregenden Aufgabe der Schreiben von Tests zu begegnen, insbesondere wenn Sie wissen, dass Ihr Code ordnungsgemäß funktioniert.
Dennoch ist die Aufgabe des Schreibens von Tests viel erfüllender als Stunden am manuellen Testen Ihrer Anwendung oder am Versuch, die Ursache eines neu aufgetretenen Problems zu identifizieren.
Es ist ein Fehler, Tests lediglich als einen negativen Aspekt der Entwicklung zu betrachten.
Ohne Tests kann der Zweck oder das beabsichtigte Verhalten einer Anwendung ziemlich undurchsichtig sein. Selbst wenn es Ihr eigener Code ist, werden Sie sich manchmal darin herumtappen, um herauszufinden, was er genau macht.
Tests ändern das; sie beleuchten Ihren Code von innen heraus, und wenn etwas schiefgeht, richten sie das Licht auf den Teil, der fehlerhaft ist – auch wenn Sie nicht einmal bemerkt haben, dass etwas schiefgeht.
Sie könnten ein brillantes Softwarestück erstellt haben, aber Sie werden feststellen, dass viele andere Entwickler es ablehnen, weil es keine Tests hat; ohne Tests vertrauen sie es nicht. Jacob Kaplan-Moss, einer der ursprünglichen Django-Entwickler, sagt: „Code ohne Tests ist von der Design her fehlerhaft.“
Der Grund, warum andere Entwickler Tests in Ihrer Software sehen möchten, bevor sie es ernst nehmen, ist noch ein weiterer Grund für Sie, anfangen, Tests zu schreiben.
Die vorherigen Punkte sind aus der Sicht eines einzelnen Entwicklers geschrieben, der eine Anwendung unterhält. Komplexe Anwendungen werden von Teams unterhalten. Tests gewährleisten, dass Kollegen Ihren Code nicht versehentlich kaputt machen (und dass Sie auch nicht den ihren ohne zu wissen). Wenn Sie als Django-Programmierer leben möchten, müssen Sie gut im Schreiben von Tests sein!
Es gibt viele Wege, um Tests zu schreiben.
Einige Programmierer folgen einer Disziplin namens "testgetriebene Entwicklung"; sie schreiben tatsächlich ihre Tests, bevor sie ihren Code schreiben. Dies mag zunächst gegenintuitive erscheinen, ist aber tatsächlich ähnlich dem, was die meisten Menschen sowieso oft tun: Sie beschreiben ein Problem und erstellen dann Code, um es zu lösen. Die testgetriebene Entwicklung formalisieren das Problem in einem Python-Testfall.
Oft werden Anfänger beim Testen zuerst Code erstellen und später entscheiden, dass dieser Tests benötigen sollte. Vielleicht wäre es besser gewesen, Tests früher zu schreiben, aber es ist nie zu spät, um zu beginnen.
Manchmal ist es schwierig, herauszufinden, wo man mit dem Schreiben von Tests beginnen soll. Wenn Sie bereits mehrere tausend Zeilen Python-Code geschrieben haben, kann es nicht einfach sein, etwas auszuwählen, das getestet werden soll. In einem solchen Fall lohnt es sich, Ihren ersten Test beim nächsten Codeänderungsschritt zu schreiben, sei es, wenn Sie eine neue Funktion hinzufügen oder einen Bug beheben.
Lassen Sie uns daher sofort loslegen.
Zum Glück gibt es in der Umfrage
-Anwendung einen kleinen Bug, den wir sofort beheben können: Die Methode Question.was_published_recently()
gibt True
zurück, wenn die Question
innerhalb des letzten Tages veröffentlicht wurde (was korrekt ist), aber auch wenn das pub_date
-Feld der Question
in der Zukunft liegt (was sicherlich nicht der Fall ist).
Bestätigen Sie den Bug, indem Sie die shell
verwenden, um die Methode für eine Frage zu überprüfen, deren Datum in der Zukunft liegt:
cd ~/project/mysite
python manage.py shell
>>> import datetime
>>> from django.utils import timezone
>>> from polls.models import Question
>>> ## Erstellen Sie eine Question-Instanz mit pub_date 30 Tage in der Zukunft
>>> future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))
>>> ## Wurde sie kürzlich veröffentlicht?
>>> future_question.was_published_recently()
True
Da Dinge in der Zukunft nicht „kürzlich“ sind, ist dies eindeutig falsch.
Was wir gerade in der shell
getan haben, um das Problem zu testen, können wir genauso in einem automatisierten Test tun. Lassen Sie uns daher das in einen automatisierten Test umwandeln.
Ein üblicher Ort für die Tests einer Anwendung ist die tests.py
-Datei der Anwendung; das Testsystem findet automatisch Tests in jeder Datei, deren Name mit test
beginnt.
Fügen Sie Folgendes in die tests.py
-Datei in der Umfrage
-Anwendung hinzu:
import datetime
from django.test import TestCase
from django.utils import timezone
from.models import Question
class QuestionModelTests(TestCase):
def test_was_published_recently_with_future_question(self):
"""
was_published_recently() gibt False für Fragen zurück, deren pub_date
in der Zukunft liegt.
"""
time = timezone.now() + datetime.timedelta(days=30)
future_question = Question(pub_date=time)
self.assertIs(future_question.was_published_recently(), False)
Hier haben wir eine Unterklasse von django.test.TestCase
erstellt, die eine Methode enthält, die eine Question
-Instanz mit einem pub_date
in der Zukunft erstellt. Wir überprüfen dann die Ausgabe von was_published_recently()
– die sollte False
sein.
Im Terminal können wir unseren Test ausführen:
python manage.py test polls
und Sie werden etwas wie Folgendes sehen:
[object Object]
Anderer Fehler?
Wenn Sie hier stattdessen einen NameError
erhalten, haben Sie vielleicht einen Schritt in Teil 2 <tutorial02-import-timezone>
übersehen, in dem wir die Imports von datetime
und timezone
in polls/models.py
hinzugefügt haben. Kopieren Sie die Imports aus diesem Abschnitt und versuchen Sie, Ihre Tests erneut auszuführen.
Was passiert ist Folgendes:
manage.py test polls
suchte nach Tests in der Umfrage
-Anwendungdjango.test.TestCase
-Klassetest
beginnentest_was_published_recently_with_future_question
erstellte es eine Question
-Instanz, deren pub_date
-Feld 30 Tage in der Zukunft istassertIs()
-Methode stellte es fest, dass ihre was_published_recently()
True
zurückgibt, obwohl wir wollten, dass sie False
zurückgibtDer Test informiert uns, welcher Test fehlgeschlagen ist und sogar die Zeile, an der der Fehler aufgetreten ist.
Wir wissen bereits, was das Problem ist: Question.was_published_recently()
sollte False
zurückgeben, wenn sein pub_date
in der Zukunft liegt. Ändern Sie die Methode in models.py
, sodass sie nur True
zurückgibt, wenn das Datum auch in der Vergangenheit liegt:
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
und führen Sie den Test erneut aus:
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Destroying test database for alias 'default'...
Nachdem wir einen Bug identifiziert haben, haben wir einen Test geschrieben, der ihn aufdeckt, und den Bug im Code korrigiert, sodass unser Test bestanden wird.
In Zukunft könnten viele andere Dinge mit unserer Anwendung schiefgehen, aber wir können sicher sein, dass wir diesen Bug nicht versehentlich wieder einführen, da das Ausführen des Tests uns sofort warnen wird. Wir können diese kleine Teilmenge der Anwendung als sicher für immer betrachten.
Während wir hier sind, können wir die Methode was_published_recently()
weiter festlegen; tatsächlich wäre es eher peinlich, wenn wir bei der Behebung eines Bugs einen anderen eingeführt hätten.
Fügen Sie zwei weitere Testmethoden zur gleichen Klasse hinzu, um das Verhalten der Methode umfassender zu testen:
def test_was_published_recently_with_old_question(self):
"""
was_published_recently() gibt False für Fragen zurück, deren pub_date
älter als 1 Tag ist.
"""
time = timezone.now() - datetime.timedelta(days=1, seconds=1)
old_question = Question(pub_date=time)
self.assertIs(old_question.was_published_recently(), False)
def test_was_published_recently_with_recent_question(self):
"""
was_published_recently() gibt True für Fragen zurück, deren pub_date
innerhalb des letzten Tages liegt.
"""
time = timezone.now() - datetime.timedelta(hours=23, minutes=59, seconds=59)
recent_question = Question(pub_date=time)
self.assertIs(recent_question.was_published_recently(), True)
Und jetzt haben wir drei Tests, die bestätigen, dass Question.was_published_recently()
sinnvolle Werte für vergangene, aktuelle und zukünftige Fragen zurückgibt.
Wiederum ist Umfrage
eine minimale Anwendung, aber wie komplex auch immer sie in Zukunft wird und mit welchen anderen Code sie interagiert, wir haben jetzt die Gewähr, dass die Methode, für die wir Tests geschrieben haben, wie erwartet verhalten wird.
Die Umfrageanwendung ist ziemlich uneingeschränkt: Sie wird jede Frage veröffentlichen, einschließlich solcher, deren pub_date
-Feld in der Zukunft liegt. Wir sollten dies verbessern. Ein pub_date
in der Zukunft sollte bedeuten, dass die Frage zu diesem Zeitpunkt veröffentlicht wird, aber bis dahin unsichtbar.
Als wir oben den Bug behebt haben, haben wir zuerst den Test geschrieben und dann den Code, um ihn zu beheben. Tatsächlich war das ein Beispiel für testgetriebene Entwicklung, aber es spielt eigentlich keine Rolle, in welcher Reihenfolge wir die Arbeit erledigen.
In unserem ersten Test haben wir uns eng auf das interne Verhalten des Codes konzentriert. Für diesen Test möchten wir überprüfen, wie es sich verhält, wenn ein Benutzer es über einen Webbrowser erlebt.
Bevor wir versuchen, etwas zu beheben, schauen wir uns die zur Verfügung stehenden Tools an.
Django stellt einen Testclient ~django.test.Client
zur Verfügung, um die Interaktion eines Benutzers mit dem Code auf Ansichts Ebene zu simulieren. Wir können ihn in tests.py
oder sogar in der shell
verwenden.
Wir beginnen wieder mit der shell
, wo wir ein paar Dinge tun müssen, die in tests.py
nicht erforderlich sind. Das erste ist, die Testumgebung in der shell
einzurichten:
python manage.py shell
>>> from django.test.utils import setup_test_environment
>>> setup_test_environment()
~django.test.utils.setup_test_environment
installiert einen Template-Renderer, der uns ermöglicht, einige zusätzliche Attribute auf Antworten wie response.context
zu untersuchen, die sonst nicht verfügbar wären. Beachten Sie, dass diese Methode nicht eine Testdatenbank einrichtet, sodass die folgenden Befehle gegen die vorhandene Datenbank ausgeführt werden und die Ausgabe je nach den Fragen, die Sie bereits erstellt haben, etwas unterschiedlich aussehen kann. Sie können unerwartete Ergebnisse erhalten, wenn Ihre TIME_ZONE
in settings.py
nicht korrekt ist. Wenn Sie sich nicht daran erinnern, sie früher eingestellt zu haben, überprüfen Sie sie, bevor Sie fortfahren.
Als nächstes müssen wir die Testclient-Klasse importieren (später in tests.py
werden wir die django.test.TestCase
-Klasse verwenden, die ihren eigenen Client mitbringt, sodass dies nicht erforderlich sein wird):
>>> from django.test import Client
>>> ## Erstellen Sie eine Instanz des Clients für unseren Gebrauch
>>> client = Client()
Mit diesem eingerichtet können wir dem Client fragen, uns einige Arbeit zu leisten:
>>> ## Holen Sie sich eine Antwort von '/'
>>> response = client.get("/")
Not Found: /
>>> ## Wir sollten von dieser Adresse eine 404 erwarten; wenn Sie stattdessen
>>> ## einen "Invalid HTTP_HOST header"-Fehler und eine 400-Antwort sehen, haben
>>> ## Sie wahrscheinlich den oben beschriebenen Aufruf von setup_test_environment()
>>> ## übersehen.
>>> response.status_code
404
>>> ## Andererseits sollten wir etwas auf '/polls/' finden
>>> ## Wir verwenden'reverse()' anstelle einer hartcodierten URL
>>> from django.urls import reverse
>>> response = client.get(reverse("polls:index"))
>>> response.status_code
200
>>> response.content
b'\n <ul>\n \n <li><a href="/polls/1/">What's up?</a></li>\n \n </ul>\n\n'
>>> response.context["latest_question_list"]
<QuerySet [<Question: What's up?>]>
Die Liste der Umfragen zeigt Umfragen an, die noch nicht veröffentlicht sind (d.h. die, die ein pub_date
in der Zukunft haben). Lassen Sie uns das beheben.
In **Form Processing and Cutting Down Our Code**
haben wir eine klassengebasierte Ansicht eingeführt, basierend auf ~django.views.generic.list.ListView
:
class IndexView(generic.ListView):
template_name = "polls/index.html"
context_object_name = "latest_question_list"
def get_queryset(self):
"""Return the last five published questions."""
return Question.objects.order_by("-pub_date")[:5]
Wir müssen die get_queryset()
-Methode ändern und so umgestalten, dass sie auch das Datum überprüft, indem es mit timezone.now()
verglichen wird. Zunächst müssen wir einen Import hinzufügen:
from django.utils import timezone
und dann müssen wir die get_queryset
-Methode wie folgt ändern:
def get_queryset(self):
"""
Return the last five published questions (not including those set to be
published in the future).
"""
return Question.objects.filter(pub_date__lte=timezone.now()).order_by("-pub_date")[
:5
]
Question.objects.filter(pub_date__lte=timezone.now())
gibt einen QuerySet zurück, der Question
s enthält, deren pub_date
kleiner oder gleich - d.h. früher oder gleich - timezone.now
ist.
Jetzt können Sie sich vergewissern, dass dies wie erwartet funktioniert, indem Sie runserver
starten, die Website in Ihrem Browser laden, Questions
mit Daten in der Vergangenheit und Zukunft erstellen und überprüfen, dass nur die veröffentlichten aufgelistet werden. Sie möchten nicht jedes Mal, wenn Sie eine Änderung vornehmen, die dies möglicherweise beeinflusst, dazu gezwungen sein, dies zu tun - also erstellen wir auch einen Test, basierend auf unserer obigen shell
-Session.
Fügen Sie Folgendes zu polls/tests.py
hinzu:
from django.urls import reverse
und wir erstellen eine Kurzschreibfunktion, um Fragen zu erstellen, sowie eine neue Testklasse:
def create_question(question_text, days):
"""
Create a question with the given `question_text` and published the
given number of `days` offset to now (negative for questions published
in the past, positive for questions that have yet to be published).
"""
time = timezone.now() + datetime.timedelta(days=days)
return Question.objects.create(question_text=question_text, pub_date=time)
class QuestionIndexViewTests(TestCase):
def test_no_questions(self):
"""
If no questions exist, an appropriate message is displayed.
"""
response = self.client.get(reverse("polls:index"))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "No polls are available.")
self.assertQuerySetEqual(response.context["latest_question_list"], [])
def test_past_question(self):
"""
Questions with a pub_date in the past are displayed on the
index page.
"""
question = create_question(question_text="Past question.", days=-30)
response = self.client.get(reverse("polls:index"))
self.assertQuerySetEqual(
response.context["latest_question_list"],
[question],
)
def test_future_question(self):
"""
Questions with a pub_date in the future aren't displayed on
the index page.
"""
create_question(question_text="Future question.", days=30)
response = self.client.get(reverse("polls:index"))
self.assertContains(response, "No polls are available.")
self.assertQuerySetEqual(response.context["latest_question_list"], [])
def test_future_question_and_past_question(self):
"""
Even if both past and future questions exist, only past questions
are displayed.
"""
question = create_question(question_text="Past question.", days=-30)
create_question(question_text="Future question.", days=30)
response = self.client.get(reverse("polls:index"))
self.assertQuerySetEqual(
response.context["latest_question_list"],
[question],
)
def test_two_past_questions(self):
"""
The questions index page may display multiple questions.
"""
question1 = create_question(question_text="Past question 1.", days=-30)
question2 = create_question(question_text="Past question 2.", days=-5)
response = self.client.get(reverse("polls:index"))
self.assertQuerySetEqual(
response.context["latest_question_list"],
[question2, question1],
)
Schauen wir uns einige davon genauer an.
Zunächst ist eine Frage-Kurzschreibfunktion, create_question
, um einige Wiederholungen beim Erstellen von Fragen zu vermeiden.
test_no_questions
erstellt keine Fragen, sondern überprüft die Nachricht: "No polls are available." und verifiziert, dass die latest_question_list
leer ist. Beachten Sie, dass die django.test.TestCase
-Klasse einige zusätzliche Assertionsmethoden bietet. In diesen Beispielen verwenden wir ~django.test.SimpleTestCase.assertContains()
und ~django.test.TransactionTestCase.assertQuerySetEqual()
.
In test_past_question
erstellen wir eine Frage und überprüfen, dass sie in der Liste erscheint.
In test_future_question
erstellen wir eine Frage mit einem pub_date
in der Zukunft. Die Datenbank wird für jede Testmethode zurückgesetzt, sodass die erste Frage nicht mehr vorhanden ist, und daher sollte auch der Index keine Fragen enthalten.
Und so weiter. Tatsächlich verwenden wir die Tests, um eine Geschichte über die Admin-Eingabe und die Benutzererfahrung auf der Website zu erzählen und zu überprüfen, dass in jedem Zustand und für jede neue Änderung im Zustand des Systems die erwarteten Ergebnisse veröffentlicht werden.
DetailView
Was wir haben, funktioniert gut; jedoch können Benutzer, auch wenn zukünftige Fragen nicht im Index erscheinen, immer noch auf sie zugreifen, wenn sie die richtige URL kennen oder erraten. Wir müssen daher eine ähnliche Einschränkung für die DetailView
hinzufügen:
class DetailView(generic.DetailView):
...
def get_queryset(self):
"""
Excludes any questions that aren't published yet.
"""
return Question.objects.filter(pub_date__lte=timezone.now())
Wir sollten dann einige Tests hinzufügen, um zu überprüfen, dass eine Question
, deren pub_date
in der Vergangenheit ist, angezeigt werden kann, und dass eine mit einem pub_date
in der Zukunft nicht angezeigt wird:
class QuestionDetailViewTests(TestCase):
def test_future_question(self):
"""
The detail view of a question with a pub_date in the future
returns a 404 not found.
"""
future_question = create_question(question_text="Future question.", days=5)
url = reverse("polls:detail", args=(future_question.id,))
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
def test_past_question(self):
"""
The detail view of a question with a pub_date in the past
displays the question's text.
"""
past_question = create_question(question_text="Past Question.", days=-5)
url = reverse("polls:detail", args=(past_question.id,))
response = self.client.get(url)
self.assertContains(response, past_question.question_text)
Wir sollten eine ähnliche get_queryset
-Methode zu ResultsView
hinzufügen und eine neue Testklasse für diese Ansicht erstellen. Es wird sehr ähnlich zu dem, was wir gerade erstellt haben; tatsächlich wird es eine Menge Wiederholungen geben.
Wir könnten unsere Anwendung auch auf andere Weise verbessern und dabei Tests hinzufügen. Beispielsweise ist es dumm, dass Questions
auf der Website veröffentlicht werden können, die keine Choices
haben. Unsere Ansichten könnten daher darauf prüfen und solche Questions
ausschließen. Unsere Tests würden eine Question
ohne Choices
erstellen und dann testen, dass sie nicht veröffentlicht wird, sowie eine ähnliche Question
mit Choices
erstellen und testen, dass sie veröffentlicht wird.
Vielleicht sollten angemeldete Admin-Benutzer nicht veröffentlichte Questions
sehen können, aber normale Besucher schon. Wieder: Alles, was zur Software hinzugefügt werden muss, um dies zu erreichen, sollte von einem Test begleitet werden, ob Sie den Test zuerst schreiben und dann den Code so gestalten, dass er den Test besteht, oder zuerst die Logik in Ihrem Code erarbeiten und dann einen Test schreiben, um es zu beweisen.
Nach einer gewissen Zeit werden Sie sicherlich auf Ihre Tests schauen und sich fragen, ob Ihr Code unter Testüberflutung leidet, was uns zu:
Es mag so aussehen, als würden unsere Tests außer Kontrolle geraten. In diesem Tempo wird es bald mehr Code in unseren Tests geben als in unserer Anwendung, und die Wiederholungen wirken unästhetisch im Vergleich zur eleganten Kürze des restlichen Codes.
Es spielt keine Rolle. Lassen Sie sie wachsen. Großteils können Sie einen Test einmal schreiben und dann vergessen. Er wird seine nützliche Funktion weiterhin erfüllen, während Sie Ihr Programm weiterentwickeln.
Manchmal müssen die Tests aktualisiert werden. Nehmen wir an, dass wir unsere Ansichten so ändern, dass nur Questions
mit Choices
veröffentlicht werden. In diesem Fall werden viele unserer bestehenden Tests fehlschlagen - und das sagt uns genau, welche Tests geändert werden müssen, um sie auf dem neuesten Stand zu bringen - sofern Tests sich in gewisser Weise selber pflegen.
Im schlimmsten Fall können Sie beim weiteren Entwickeln feststellen, dass Sie einige Tests jetzt redundant sind. Auch das ist kein Problem; in der Testwelt ist Redundanz ein gutes Ding.
Solange Ihre Tests vernünftig strukturiert sind, werden sie nicht unüberwaltigbar. Gute allgemeine Regeln sind:
TestClass
für jedes Modell oder jede AnsichtIn diesem Tutorial werden nur einige der Grundlagen des Testens vorgestellt. Es gibt noch viel mehr, was Sie tun können, und eine Reihe sehr nützlicher Tools, mit denen Sie sehr intelligente Dinge erreichen können.
Zum Beispiel haben unsere Tests hier einige der internen Logik eines Modells und die Art, wie unsere Ansichten Informationen veröffentlichen, abgedeckt, aber Sie können ein "in-browser"-Framework wie Selenium verwenden, um zu testen, wie Ihre HTML-Seite tatsächlich in einem Browser gerendert wird. Mit diesen Tools können Sie nicht nur das Verhalten Ihres Django-Codes, sondern auch beispielsweise das von Ihrem JavaScript überprüfen. Es ist ziemlich beeindruckend, zu sehen, wie die Tests einen Browser starten und mit Ihrer Website interagieren, als ob ein Mensch sie bediene! Django enthält ~django.test.LiveServerTestCase
, um die Integration mit Tools wie Selenium zu erleichtern.
Wenn Sie eine komplexe Anwendung haben, möchten Sie möglicherweise Tests automatisch mit jedem Commit für die Zwecke der kontinuierlichen Integration ausführen, so dass die Qualitätssicherung zumindest teilweise automatisiert ist.
Ein guter Weg, um ungetestete Teile Ihrer Anwendung zu entdecken, ist die Prüfung der Codeabdeckung. Dies hilft auch, fragiles oder sogar todes 代码 zu identifizieren. Wenn Sie einen Codeausschnitt nicht testen können, bedeutet das normalerweise, dass der Code umgebaut oder entfernt werden sollte. Die Abdeckung wird helfen, todes 代码 zu identifizieren. Einzelheiten finden Sie unter topics-testing-code-coverage
.
Testing in Django </topics/testing/index>
enthält umfassende Informationen zum Testen.
Herzlichen Glückwunsch! Sie haben das Labor "Create Some Automated Tests" abgeschlossen. Sie können in LabEx weitere Labs absolvieren, um Ihre Fähigkeiten zu verbessern.