# 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/