Wenn man eine Django-App erstellt, wird automatisch auch eine tests.py erstellt.
Die meisten Entwickler haben einmal diese Gedanken.
„Kann man diese Datei… einfach löschen?“
„Wie wird sie überhaupt genutzt?“
Tatsächlich ist tests.py der offiziell empfohlene Einstiegspunkt für Tests in Django, und
wenn man sich ein wenig daran gewöhnt, wird es bei Refactorings, Funktionshinzufügungen und Versionsupdates eine echte große Versicherung. (Django-Projekt)
In diesem Beitrag werden wir:
-
Was ist die Funktion von
tests.py? -
Wie man es schreibt und ausführt
-
In welchen Situationen es besonders nützlich ist
-
Beispiele aus der Praxis
alles auf einen Blick zusammenfassen.
1. Was ist tests.py?
Django verwendet ein Test-Framework, das auf der unittest-Standardbibliothek von Python basiert.
-
Erstelle Testklassen, die von
django.test.TestCaseerben, und -
schreibe Methoden, die mit
test_beginnen -
und diese werden automatisch mit dem Befehl
./manage.py testgefunden und ausgeführt.
Wenn du mit startapp eine App erstellst, wird standardmäßig tests.py erstellt:
-
Kleine Projekte → genügt ein
tests.py -
Bei größeren Projekten → wird empfohlen, in ein
tests/-Paket zu splitten (test_models.py,test_views.pyusw.)
Das heißt, du kannst es als „den Basissitz für tests der App“ verstehen.
2. Wann ist es nützlich? (Warum sollte man Tests verwenden?)
Django-Tests sind besonders in den folgenden Situationen wertvoll.
-
Überprüfung von Modellen/Geschäftslogik
-
Je komplizierter die Berechnung, Statusänderungen und benutzerdefinierte Methoden sind,
-
kann man nach einmaligem Testen mit besserem Gefühl refactoren.
-
-
Überprüfung von Views/URLs/Berechtigungen
-
Unterscheidet sich der Antwortcode basierend auf der Authentifizierung?
-
Wird bei falschen Eingaben korrekt weitergeleitet bzw. Fehler behandelt?
-
Wird der benötigte Kontext für die Templates korrekt übermittelt?
-
-
Verhinderung von Rückschritt-Bugs
- Wenn ein Bug einmal behoben ist, sollte er mit einem Test festgehalten werden, damit das gleiche Problem nicht erneut auftritt.
-
Gewährleistung der Stabilität bei Versionsupdates
-
Wenn die Django-Version oder die Bibliotheksversion aktualisiert wird,
-
kannst du sicherstellen, dass du mit
./manage.py testprüfst.
-
3. Ein grundlegendes Beispiel für tests.py
3-1. Modell-Test
# myapp/tests.py
from django.test import TestCase
from .models import Article
class ArticleModelTests(TestCase):
def setUp(self):
self.article = Article.objects.create(
title="Testtitel",
content="Inhalt",
views=0,
)
def test_increase_views(self):
# gegeben
self.assertEqual(self.article.views, 0)
# wenn
self.article.increase_views()
# dann
self.assertEqual(self.article.views, 1)
-
TestCaseist eine Klasse für Django, dieunittest.TestCaseerweitert. -
Jeder Test wird isoliert auf Transaktionsebene durchgeführt, und die Datenbank wird für jeden Test zurückgerollt, sodass sie sich nicht beeinflussen.
4. Wie man Views/URLs testet – Verwendung von Client
Django stellt einen HTTP-Client für Tests zur Verfügung: django.test.Client.
Damit kannst du GET/POST-Anfragen an URLs senden und die Antworten überprüfen, ohne einen tatsächlichen Server zu starten.
4-1. Einfacher View-Test
# myapp/tests.py
from django.test import TestCase
from django.urls import reverse
from .models import Article
class ArticleViewTests(TestCase):
def setUp(self):
self.article = Article.objects.create(
title="Beitrag 1",
content="Inhalt",
views=0,
)
def test_article_detail_page_returns_200(self):
url = reverse("article_detail", args=[self.article.id])
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Beitrag 1")
Der Schlüssel ist hier:
-
self.client: eine Test Client-Instanz, die standardmäßig inTestCasebereitgestellt wird -
reverse("article_detail", args=[...]): vergangene URLs operiert als URL-Namen anstelle von Hardcodierungen -
assertContains: überprüft, ob ein bestimmter String im Antwortkörper enthalten ist.
4-2. Testen von Login/Berechtigungen
from django.contrib.auth import get_user_model
class ArticlePermissionTests(TestCase):
def setUp(self):
self.user = get_user_model().objects.create_user(
username="tester",
password="pass1234",
)
self.article = Article.objects.create(
title="geheim",
content="Geheimtext",
views=0,
)
def test_anonymous_user_redirected_to_login(self):
url = reverse("article_edit", args=[self.article.id])
response = self.client.get(url)
self.assertEqual(response.status_code, 302)
self.assertIn("/accounts/login", response["Location"])
def test_logged_in_user_can_access_edit_page(self):
self.client.login(username="tester", password="pass1234")
url = reverse("article_edit", args=[self.article.id])
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
-
überprüfen, ob ein anonymer Benutzer weitergeleitet wird
-
überprüfen, ob ein eingeloggter Benutzer normal zugreifen kann
Wir können so Bugs im Zusammenhang mit Berechtigungen in einem frühen Stadium herausfiltern.
5. Wann/wie führt man tests.py aus?
5-1. Alle Tests ausführen
$ python manage.py test
- Es durchsucht alle
test*.py-Dateien im aktuellen Verzeichnis und führt
unittest.TestCaseoderdjango.test.TestCase-Unterklassen automatisch aus.
5-2. Nur bestimmte Apps ausführen
$ python manage.py test myapp
5-3. Nur bestimmte Module/Klassen/Methoden ausführen
# Module myapp.tests komplett
$ python manage.py test myapp.tests
# Bestimmtes TestCase
$ python manage.py test myapp.tests.ArticleViewTests
# Bestimmte Testmethode
$ python manage.py test myapp.tests.ArticleViewTests.test_article_detail_page_returns_200
Es ist gut, sich während der Entwicklung den Ritual, die geänderten Teile schnell zu testen anzueignen.
6. Erweiterung von tests.py zu einem tests-Paket
Wenn das Projekt wächst, lässt sich tests.py nicht mehr allein bewältigen.
Django-Dokumentationen raten auch dazu, die Struktur zu verpacken. (Django-Projekt)
Beispiel:
myapp/
tests/
__init__.py
test_models.py
test_views.py
test_forms.py
test_api.py
In jeder Datei:
# myapp/tests/test_models.py
from django.test import TestCase
from myapp.models import Article
class ArticleModelTests(TestCase):
...
Wenn du es so aufteilst, bleibt die Ausführung gleich.
$ python manage.py test myapp # alles
$ python manage.py test myapp.tests.test_models # nur Modelle-Tests
7. Einige Anwendungsfälle aus der Praxis
7-1. „Bug-Reproduktionsprobe“ zur Verhinderung von Rückschritten
-
Ein Bug tritt in der Produktion auf
-
Schreibe einen Reproduktionstest lokal (muss fehlschlagen)
-
Code anpassen
-
Bestätige, dass der Test erfolgreich ist
-
Commite
gitTest + angepasster Code zusammen
Auf diese Weise wird derselbe Bug beim Refactoring nicht wieder auftreten.
7-2. Festlegung von API-Antwortformaten
Bei der Zusammenarbeit mit dem Frontend ist das Format der API-Antwort von großer Bedeutung.
class ArticleApiTests(TestCase):
def setUp(self):
self.article = Article.objects.create(
title="API Titel",
content="Inhalt",
views=0,
)
def test_article_detail_api_response(self):
url = reverse("api:article-detail", args=[self.article.id])
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
data = response.json()
self.assertEqual(data["id"], self.article.id)
self.assertIn("title", data)
self.assertIn("content", data)
-
Gibt an, welche Felder unbedingt in der Antwort enthalten sein müssen
-
Wenn du einen Feldnamen versehentlich änderst oder entfernst, schlägt der Test sofort fehl
7-3. Testen der Formularvalidierungslogik
from .forms import ArticleForm
class ArticleFormTests(TestCase):
def test_title_is_required(self):
form = ArticleForm(data={"title": "", "content": "Inhalt"})
self.assertFalse(form.is_valid())
self.assertIn("title", form.errors)
def test_valid_form(self):
form = ArticleForm(data={"title": "Titel", "content": "Inhalt"})
self.assertTrue(form.is_valid())
- Die Regeln der Validierung für das Formular können dokumentiert und als Tests festgehalten werden.

8. Zusammenfassung – Löscht tests.py nicht, sondern schreibt es einmal richtig
Zusammengefasst:
tests.pyist die Datei, die „ein Sicherheitsnetz für Django-Apps“ schafft.
-
Es ist anfangs lästig,
-
aber wenn du einmal den Entwicklungsfluss basierend auf Tests erlebst,
-
wird der Stress bei Refactorings/Funktionshinzufügungen/Versionsupdates deutlich weniger.
In tatsächlichen Projekten:
-
Wenn du eine neue Funktion entwickelst – füge mindestens 1–2 Tests hinzu
-
Wenn du einen Bug behebst – schreibe zuerst den Test, der den Bug reproduziert
-
Wenn du das Projekt zu wachsen beginnst – refactoriere
tests.pyzu einemtests/-Paket
Wenn du diesem Muster folgst, wirst du eine ganz andere Entwicklerfahrung haben als bei einem „Django-Projekt ohne Tests“.
Es sind keine Kommentare vorhanden.