Dieses Mal werde ich neben den Funktionen der App auf das Testen eingehen.
Früher habe ich so etwas gemacht, um einen Job zu bekommen, aber als ich ihn tatsächlich veröffentlicht habe und die verantwortliche Person ihn beim Interview oder von der Person, die ihn berührt hat, gesehen habe, den Rahmen Viele Leute wiesen darauf hin, dass sie nicht genug verstanden. Einer von ihnen war, dass es keinen Testcode gab.
Aus dem offiziellen Tutorial
Warum müssen Sie einen Test erstellen? Warum einen Test machen? Und warum jetzt? Vielleicht sind Sie zu beschäftigt damit, Python oder Django zu lernen, und etwas anderes zu lernen, mag entmutigend und unnötig erscheinen. Dies liegt daran, dass die Abstimmungsanwendung einwandfrei funktioniert und die Einführung automatisierter Tests die Anwendung nicht verbessert. Wenn der einzige Zweck des Lernens der Django-Programmierung darin besteht, diese Abstimmungsanwendung zu erstellen, müssen Sie sicher keine automatisierten Tests implementieren. Wenn nicht, ist jetzt der perfekte Zeitpunkt, um mehr über automatisierte Tests zu erfahren.
Das offizielle Tutorial führt den Test ebenfalls auf diese Weise ein. Warum also einen Test schreiben?
Wenn Sie die Algorithmusüberprüfung automatisieren und integrieren und Änderungen an einem der Elemente vornehmen, aus denen das System besteht, funktioniert dies nicht ordnungsgemäß. Wenn nicht, was ist das Problem? Sie können sofort erfassen, ob oder nicht.
Umgekehrt beweist die Fähigkeit, Code zur Überprüfung eines Algorithmus zu schreiben, dass Sie diesen Algorithmus gut verstehen.
Ich hatte das Gefühl, dass es grob in diese beiden Punkte unterteilt war. Ersteres ist aus Sicht der sogenannten Vollständigkeit und Wartung wichtig. Besonders wenn Sie ein Anfänger wie wir sind
Aus dem offiziellen Tutorial
Das Schreiben von Tests kann Teams bei der Zusammenarbeit unterstützen. Bisher habe ich aus der Perspektive eines Entwicklers geschrieben, der die Anwendung wartet. Komplexe Anwendungen werden jedoch im Team gepflegt. Das Testen schützt Sie vor versehentlichem Brechen von Code, den Sie schreiben (und auch vor dem Brechen von Code, der von anderen geschrieben wurde). Wenn Sie als Django-Programmierer leben möchten, müssen Sie auf jeden Fall gute Tests schreiben!
Mir fehlt diese Art des Denkens, aber selbst wenn ich es alleine mache, werde ich es als Team machen, weil das gestrige Ich, mein Tippfehler vor ein paar Stunden und seltsamer Code den Code, den ich jetzt geschrieben habe, behindern werden. Wenn es darum geht, ist es nicht schwer vorstellbar, dass ein Risiko besteht.
In Bezug auf Letzteres hatte ich das Gefühl, dass ich mich erst nach dem Test als Programmierer bezeichnen konnte. Lass uns weitermachen.
Meinung, einen Test zu schreiben und dann Code zu schreiben → Es basiert auf der Theorie, dass Sie Code schreiben können, wenn Sie einen Test schreiben. Klären Sie das Problem mit dem Prozess, den Sie erreichen möchten, bevor Sie mit dem Schreiben von Code beginnen.
Meinung, Code zu schreiben und dann zu testen → Schreiben Sie nach der Theorie, ob der von Ihnen geschriebene Code normal funktioniert.
Fügen Sie neue Funktionen hinzu, überprüfen Sie Fehler und ändern Sie vorhandene Komponenten.
Ich weiß nicht, welche die richtige Antwort ist, aber ich denke, die Person, die 1 kann, ist bereits ein guter Programmierer. Dann denke ich, dass wir Anfänger darauf abzielen, uns bewusst zu werden, dass wir zur dritten Stufe übergehen, die ein Kompromiss zwischen 1 und 2 ist.
Sich die Zeit zu nehmen, um einen Test zu schreiben, ist ein guter Umweg unter dem Gesichtspunkt, einfach "etwas zu machen, das sich bewegt", und es ist ein Ort, an dem sich Anfänger unbehaglich fühlen.
Wie ich jedoch wiederholt sagte, können Sie, wenn Sie keinen Test schreiben können, nicht anders, als von anderen bewertet zu werden, dass Sie den von Ihnen geschriebenen Code nicht verstehen. Ich denke das entspricht 3.
Lassen Sie uns nun die Testelemente des Django-Tutorials ausführen und dabei berücksichtigen, was wir in 3 geschrieben haben.
Denken Sie daran, dass es in models einen Fehler in models.py
gab?
Dies ist ein Fehler, bei dem das sogenannte ** zukünftige Datum ** angezeigt wird.
Führen Sie den folgenden Befehl mit dem Shell-Befehl aus.
import datetime
from django.utils import timezone
from polls.models import Question
future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30)) #1
future_question.was_published_recently() #2
In 1 wird die "timedelta" -Methode verwendet, um eine Instanz eines zukünftigen Datums zu erstellen. Da "pub_date = timezone.now () + datetime.timedelta (days = 30)" eine Instanz mit Datumsinformationen 30 Tage nach dem aktuellen Datum veröffentlicht.
In 2 wird die Methode "was_published_recently ()" unter Verwendung dieser Instanz ausgeführt. Was machst du
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
Es war eine Methode, die "True" zurückgibt, wenn die Datumsinformationen der Instanz nicht in der Vergangenheit liegen, andernfalls "False" zurückgibt. Es wurde jedoch gesagt, dass es einen Fehler gibt, dass es "wahr" sein wird, selbst wenn es ein zukünftiges Datum ist. Das Ergebnis von 2 ist also auch "True". Erstellen wir nun einen Test, um diesen Fehler zu finden.
polls/tests.py
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):
time = timezone.now() + datetime.timedelta(days=30)
future_question = Question(pub_date=time)
self.assertIs(future_question.was_published_recently(), False)
Die Datei, die Tests in Django beschreibt, ist tests.py.
Importieren wir zu Beginn das TestCase-Objekt.
Die Möglichkeit, einen Test zu schreiben, besteht darin, eine Klasse zu erstellen, die django.test.TestCase
erbt, und die Methode dort zu schreiben.
Übrigens erbt es gleichzeitig mit dem Erben von "TestCase" auch "TransactionTestCase" und "SimpleTestCase".
Für Apps, die keine Datenbank verwenden, ist es besser, nur "SimpleTestCase" zu erben.
Um es einfach auszudrücken: Dieser TestCase beginnt bei der Ausführung von tests.py mit der Suche nach Klassen, die von TestCase erben.
Und wenn Sie es entdecken
Ist durchgeführt. Mit anderen Worten kann gesagt werden, dass der Test und jede Methode im Test vom Standpunkt der Anwendung etwas unabhängig sind. Referenz 1 Referenz 2
Was macht als nächstes die Methode "test_was_published_recently_with_future_question"?
assertIs (a, b)
überprüft, ob a = b
, dh future_question.was_published_recently ()
überprüft False
.Es bedeutet das. Nachdem Sie dies verstanden haben, führen wir den Test durch.
py manage.py test polls
Wenn Sie mehrere Anwendungen haben, ersetzen Sie Umfragen durch einen beliebigen Anwendungsordnernamen. Als Ausführungsergebnis
System check identified no issues (0 silenced).
F
======================================================================
FAIL: test_was_published_recently_with_future_question (polls.tests.QuestionModelTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/path/to/mysite/polls/tests.py", line 16, in test_was_published_recently_with_future_question
self.assertIs(future_question.was_published_recently(), False)
AssertionError: True is not False
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (failures=1)
Destroying test database for alias 'default'...
Sie sollten so etwas sehen.
Sie können hier sehen, dass was_published_recently ()
True für zukünftige Daten zurückgibt, da Sie den Fehler AssertionError: True is not False
erhalten.
Du hast einen Fehler gefunden.
Nachdem wir einen Fehler gefunden haben, werden wir Code schreiben, um ihn zu beheben.
# return self.pub_date >= timezone.now() - datetime.timedelta(days=1)Zu dem Folgendem
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
Wenn Sie "True" auf ein zukünftiges Datum zurücksetzen möchten, können Sie das aktuelle Datum zur Bedingungsspezifikation hinzufügen und auf den Maximalwert setzen.
Übrigens, wenn es um strenge Tests geht
polls/tests.py
def test_was_published_recently_with_old_question(self):
"""
was_published_recently() returns False for questions whose pub_date
is older than 1 day.
"""
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() returns True for questions whose pub_date
is within the last day.
"""
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)
Definieren Sie die beiden oben genannten neuen Methoden in tests.py.
Die Methode test_was_published_recently_with_old_question ()
ist eine Methode, die überprüft, obwas_published_recently ()
im vergangenen Datum True zurückgegeben hat.
Die Methode test_was_published_recently_with_recent_question ()
ist eine Methode, die überprüft, obwas_published_recently ()
True` zum aktuellen Datum zurückgibt.
Nachdem wir den Algorithmus getestet haben, werden Sie sich fragen, ob er tatsächlich in Ihrer Anwendung funktioniert.
Also, dieses Mal werde ich einen Test für View
schreiben.
Fügen Sie zunächst die folgenden Module und Testklassen zu der zuvor erstellten Klasse hinzu.
pols/tests.py
from django.urls import reverse
#Unterlassung
def create_question(question_text, days):
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):
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):
#Erstellen Sie eine Frageninstanz mit einem vergangenen Datum
create_question(question_text="Past question.", days=-30)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(
response.context['latest_question_list'],
['<Question: Past question.>']
)
def test_future_question(self):
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):
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: Past question.>']
)
def test_two_past_questions(self):
create_question(question_text="Past question 1.", days=-30)
create_question(question_text="Past question 2.", days=-5)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(
response.context['latest_question_list'],
['<Question: Past question 2.>', '<Question: Past question 1.>']
)
Die Methode "create_question" ist eine Methode zum Erstellen eines "Question" -Objekts, das "question_text" und "days" als Argumente verwendet. Da das Objekt "Frage" in den nachfolgenden Testklassen erstellt wird, definieren Sie es am Anfang, damit Sie den Code nicht jedes Mal schreiben müssen.
Werfen wir einen Blick auf die Klasse "QuestionIndexViewTests". Die "Client" -Klasse, die in der gesamten Story angezeigt wird, ist eine Klasse, die zum Testen verwendet wird und den Zugriff im Browser simuliert. Referenz Wenn Sie beispielsweise "self.client.get" schreiben, wird die tatsächliche Anforderungsverarbeitung wie "self.objects.get" getestet.
test_no_questions
ist eine Methode zum Überprüfen des Verhaltens, wenn das Objekt Question
nicht vorhanden ist.
Klicken Sie nun auf die URL mit "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'], [])
Die obigen drei überprüfen die Argumente auf die gleiche Weise wie die zuvor veröffentlichte Methode "assertIs ()".
Beispiel: "self.assertEqual (response.status_code, 200)" überprüft, ob die Seite im Browser angezeigt wird, wenn die URL früher eingegeben wurde.
Da der Zugangscode 200 ausgegeben wird, wenn die Seite normal angezeigt wird, überprüfen wir response.status_code == 200
.
Übrigens, wenn Sie den Betrieb von POST wie Formular überprüfen, wird es "self.client.post" sein.
self.assertContains ()
überprüft, ob das Argument das im zweiten Argument angegebene enthält.
In diesem Fall ist beispielsweise "context" im Rückgabewert von "self.client.get (reverse (" polls: index "))" in "response" enthalten, also die angegebene Zeichenfolge darin. Es wird überprüft, ob es gibt.
self.assertQuerysetEqual ()
prüft, ob das Abfrageset Daten enthält.
Übrigens bezieht sich der Abfragesatz auf den Datentyp wie "int" und betrachtet ihn grob als eine Reihe von Informationen, die aus dem Modell extrahiert wurden.
Dieses Mal werden wir die URL des Pfads von "polls: index" eingeben, damit die "IndexView" -Klasse ausgeführt wird.
Dann werden in der IndexView-Klasse die Daten schließlich mit der Methode get_queryset () aus der Datenbank abgerufen, sodass der Abfragesatz dort geboren wird.
Apropos
Da self.assertQuerysetEqual (response.context ['latest_question_list'], [])
in diesem Fall bedeutet, dass latest_question_list
leer ist, dh überprüft, dass keine Fragen vorhanden sind.
Gleiches gilt für die nachfolgenden Prüfmethoden.
Erstellen Sie ein "Question" -Objekt, indem Sie die Werte von "question_text" und "days" als Argumente für die definierte "create_question ()" -Methode angeben und darauf basierend testen.
In Bezug auf das Ausführungsergebnis von response.context ()
in der Vorlage
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
Da ich eine solche Beschreibung gemacht habe, habe ich "question_text" als Argument angegeben, sodass ich mich daran erinnere, dass der dort angegebene in "{{question.question_text}}" eingegeben wird. So setzt beispielsweise die Methode "test_past_question ()" die Frage "Past" hier. Deshalb
self.assertQuerysetEqual(response.context['latest_question_list'],['<Question: Past question.>'])
Es ist wichtig zu verstehen, dass eine solche Anweisung bedeutet, zu überprüfen, ob der Rückgabewert "Vergangene Frage" im HTML-Kontext in "Antwort" enthält.
Wenn Sie bisher verstanden haben, in test_future_question ()
self.assertQuerysetEqual(response.context['latest_question_list'], [])
Ich denke nicht, dass es schwierig ist, weil Sie sehen können, dass das wahr ist.
Ändern Sie abschließend vor dem Testen die Ansicht. Ich habe den Modellfehler behoben, aber das liegt daran, dass ein Objekt mit einem zukünftigen Datum angezeigt wird. Importieren Sie das Objekt "timezone" aus dem Modul "django.utils" und ändern Sie die Klasse "IndexView" wie folgt:
from django.utils import timezone
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
return Question.objects.filter(
pub_date__lte = timezone.now()
).order_by('-pub_date')[:5]
Stellen Sie sich pub_date__lte = timezone.now ()
als Synonym fürpub_date <= timezone.now ()
vor.
Mit anderen Worten, der Prozess gibt einen Abfragesatz zurück, der 5 "Frage" -Objekte mit Datumsinformationen vor dem aktuellen Datum abruft.
Obwohl es in Ordnung ist, bis zu "Index" zu korrigieren, werden die Daten des zukünftigen Datums weiterhin in "Detailansicht" angezeigt, so wie sie sind. Lassen Sie uns dies auch hier korrigieren. Ändern Sie wie folgt.
polls/views.py
class DetailView(generic.DetailView):
...
def get_queryset(self):
return Question.objects.filter(pub_date__lte=timezone.now())
Fügen Sie als Nächstes die folgende Testklasse zu tests.py
hinzu.
class QuestionDetailViewTests(TestCase):
def test_future_question(self):
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):
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
Grundsätzlich ist die Theorie die gleiche wie beim vorherigen Test. Der Unterschied besteht im DetailView-Test. Bereiten Sie daher den Teil "34" der URL wie "/ polls / 34" im Voraus in Form von "url = reverse (" polls: detail ", args = (future_question.id,))" vor. Sie müssen es als separate URL angeben.
Übrigens haben einige von Ihnen vielleicht schon einige Tests geschrieben, aber im Fall der Anwendung in diesem Tutorial müssen Sie beispielsweise einen Test für "resluts.html" schreiben, dh für die "ResultsView" -Klasse. Ich weiß, ich kann nicht. Sie können jedoch sehen, dass der Inhalt des Tests fast dem Test für die soeben geschriebene DetaiView-Klasse entspricht. Der einzige Unterschied besteht darin, dass der Teil "polls: detail" in "polls: results" geändert wird.
Andererseits geht das offizielle Dokument davon aus, dass dem Test eine Duplizierung inhärent ist, und enthält die folgenden drei Punkte als Regeln für die Organisation.
TestClass
nach Modell oder Ansicht auf
--Erstellen Sie verschiedene Testmethoden für jeden Satz von Bedingungen, die Sie testen möchtenIch überlasse Ihnen das Wissen, das Sie benötigen, um dieses Test-Tutorial auszuführen.
・ Vom Container zum Host
Name oder ID des Docker-CP-Containers: Pfad zu dem Verzeichnis oder der Datei, in die Sie das Verzeichnis des zu kopierenden Hosts kopieren möchten
・ Vom Host zum Container
Docker-CP-Pfad zu dem Verzeichnis oder der Datei, die Sie kopieren möchten. Containername oder ID: Pfad zum Speichern im Container
docker exec -it Containername/bin/bash
Betreten Sie den Container mit etc.
py -c "import django; print(django.__path__)"
Sie müssen also den Pfad der Quelldatei durchsuchen. Sie können den Speicherort des Django-Ordners finden, indem Sie den Pfad der Quelldatei durchsuchen. Wenn Sie ihn auf die Hostseite kopieren, können Sie ihn im schlimmsten Fall auf der Hostseite finden. Wenn Sie das Verzeichnis bis zur Datei kennen, können Sie es natürlich einfach hinzufügen und nur diese Datei direkt kopieren.
Diesmal habe ich den Testcode zum ersten Mal studiert, aber ich fand ihn ziemlich tiefgreifend, weil ich mich nach dem Schreiben endlich als Codierer bezeichnen konnte. Die klassenbasierte Sichtweise war ebenfalls verwirrend, aber ich denke nicht, dass dies ausreicht. Als ich jedoch den Testcode auf diese Weise schrieb, bestätigte ich den Code, den ich bisher geschrieben hatte, erneut und hielt dies für wichtig, da ich mein Verständnis erneut vertiefte, einschließlich der Teile, die unklar waren. Als Ergänzung zum Tutorial gibt es ein Kapitel, das sich nur mit dem Test befasst. Ich würde es daher gerne lesen, nachdem die folgenden Kapitel 6 und 7 beendet sind.
[Docker] Dateien zwischen Container und Host kopieren [[Django] Zusammenfassung der automatisierten Tests](https://qiita.com/okoppe8/items/eb7c3be5b9f6be244549#%E5%87%A6%E7%90%86%E3%81%AE%E6%B5%81% E3% 82% 8C) Erstellen der ersten Django-App, Teil 5
Recommended Posts