# RecipeBook – Testgetrieben entwickeln mit Django REST Framework #### Du entwickelst unter Anwendung von TDD (Test-Driven Development) ein kleines Rezeptbuch-Backend mit Django und dem Django REST Framework (DRF). Dabei schreibst du Tests mit assertEqual, um grundlegende HTTP-Fälle sowie die Authentifizierung zu prüfen. Es handelt sich hierbei um Integrationstests: Du testest das Zusammenspiel mehrerer Komponenten (Models, Views, Serializers, Authentifizierung) und überprüfst die HTTP-Antworten der API-Endpunkte in realistischen Szenarien. --- ## Aufgabe 1: Projekt starten * Erstelle ein neues Django-Projekt. * Lege eine App mit dem Namen `recipes_app` an. * Erstelle im Ordner `recipes_app` einen Unterordner `tests` und darin eine erste Testdatei namens `test_api.py` sowie `__init__.py`. * Lösche die automatisch erstellte Datei `tests.py` aus der App `recipes_app`. --- ## Aufgabe 2: Erster Test – GET /recipes-list/ liefert 200 OK * Wichtig: Bisher hast du noch keine Models, Views, urls etc. das ist korrekt und gewollt, erst der Test dann der Rest. * Schreibe den ersten Test: Die Testklasse soll `RecipeAPITestCase` heißen. * Die erste Testfunktion ruft eine (aktuell noch leere) Liste von Rezepten ab. * Der Endpunkt `/recipes-list/` soll abgefragt werden (auch wenn er zunächst noch nichts zurückgibt). * Der HTTP-Statuscode der Antwort soll 200 OK sein. * Lasse den Test nun durchlaufen, er sollte FAIL ausgeben, das ist gewollt bei TDD. * Implementiere nun alle benötigten Bestandteile (z.B. Models, Views (nutze `ModelViewSet`!), URLs, Serializers), bis der Test erfolgreich ist. **Tipp für das Modell:** Lege ein einfaches Modell `Recipe` mit folgenden Feldern an: ```python title = models.CharField(max_length=100) description = models.TextField() created_at = models.DateTimeField(auto_now_add=True) author = models.ForeignKey(User, on_delete=models.CASCADE) ``` --- ## Aufgabe 3: Zweiter Test – POST /recipes-list/ erstellt ein Rezept (201 Created) * Schreibe einen Test der testet, ob man mit einem POST ein Rezept erstellen kann. * Der Statuscode soll 201 Created sein. * Du darfst `author` manuell im Test übergeben. * Teste nun, der Test sollte funktionieren, da mit dem ModelViewSet alles abgedeckt ist. --- ### **Wichtiger Hinweis:** Bisher sind alle Tests **Happy Paths** – also erfolgreiche Anfragen ohne Fehler. Sobald Authentifizierung eingeführt wird, müssen auch **Unhappy Paths** getestet werden, z. B. fehlerhafte oder fehlende Authentifizierung. --- ## Aufgabe 4: Auth einführen * Aktiviere in der `settings.py` die `TokenAuthentication` und setze die `DEFAULT_PERMISSION_CLASSES` auf `IsAuthenticatedOrReadOnly`. * Füge die Token-Authentifizierung über `rest_framework.authtoken` zu den `INSTALLED_APPS` hinzu. * Teste erneut. Der POST-Test sollte jetzt fehlschlagen (da nicht autorisiert), weil der Statuscode sich ändert. ### **Anpassung der Tests:** Durch die Einführung der Authentifizierung ändern sich die erwarteten Statuscodes je nach Benutzerstatus. Daher empfiehlt es sich, Happy-Path-Tests (erfolgreiche Authentifizierung z.b. 200, 201) und Unhappy-Path-Tests (fehlende oder falsche Authentifizierung, z.b. 401 / 403) in **getrennten Testklassen** zu organisieren, z. B. * `RecipeAPITestCaseHappy` für erlaubte Zugriffe * `RecipeAPITestCaseUnhappy` für Fehlerfälle So bleibt der Testcode übersichtlich und besser wartbar, man möchte auch Fehler testen, da auch diese wie erwartet funktionieren sollten. * Erstelle nun einen Unhappy Path POST Test – Welchen Statuscode erwartest du nun? Es werden später noch weitere Tests mit eingeloggten Nutzern folgen. * Wenn du nun testest sollte wieder alles OK sein. > Hinweis: Hast du den 401 er Stautscode genommen? --- ## Aufgabe 5: Test – Als eingeloggter User ein Rezept erstellen (201 Created) * Erzeuge in einem neuen Happy Path Test einen User. * Authentifiziere dich per Token. * Sende ein POST und prüfe: 201 Created --- ## Aufgabe 6: Test – Rezept-Detail abrufen mit Auth (200 OK) * Erstelle im Test ein Rezept. * Rufe `/recipes-detail/<id>` auf – als eingeloggter User. * Prüfe: 200 OK. > Tipp: Nutze `kwargs` für die ID. --- ## Aufgabe 7: Leichte Umstellung des Projekts * Anstatt der `IsAuthenticatedOrReadOnly` Permission Class nutze nun `IsAuthenticated` in der `settings.py`. * Teste erneut, du solltest den auftretenden Fehler mit der Änderung eines Statuscodes lösen können (Happy/Unhappy-Path). --- ## Aufgabe 8: Test – Detailabruf ohne Auth gibt 401 * Rufe `/recipes-detail/<id>` auf – ohne eingeloggt zu sein. * Prüfe: 401 Unauthorized. --- ## Aufgabe 9: setUp Funktion * Solltest du keine setUp Funktion bisher genutzt haben könntest du diese noch naträglich hinzufügen und so deinen Code kürzen und Optimieren. --- ## Aufgabe 10 (optional): Pytest und Coverage * Richte anhand der offiziellen Doku [Pytest][pytest] und danach [Pytest Cov][pytest-cov] ein, um damit die Testabdeckung deines Projektes zu prüfen. [pytest]: https://pytest-django.readthedocs.io/en/latest/ [pytest-cov]: https://pypi.org/project/pytest-cov/