API Mocking mit Playwright: Eigene Daten statt echter API-Antworten

Viele Webanwendungen laden ihre Inhalte dynamisch von einer API nach – Listen, Tags, Artikel, Produkte. Beim Testen ist das nicht immer praktisch: Manche Zustände lassen sich mit echten Daten nur mühsam herstellen, eine langsame API bremst die Tests aus, und eine instabile Drittanbieter-API macht sie unzuverlässig.

Genau hier hilft Mocking: Playwright fängt den API-Aufruf ab und liefert stattdessen eine eigene Antwort zurück. In dieser Woche möchte ich dir dazu ein Beispiel zeigen, und dafür habe ich wieder ein eigenes Beispiel in meinem Testlab vorbereitet.

Vorbereitung

Als Testobjekt dient die folgende kleine Komponente aus dem Testlab, Abschnitt Nr.5 . Ein Klick auf den Button lädt drei Beiträge über einen echten fetch()-Aufruf nach und zeigt sie an:

Die Komponente kennt drei Zustände:

  • Die API liefert Beiträge → sie werden als Liste angezeigt
  • Die API liefert eine leere Liste → „Keine Beiträge vorhanden”
  • Die API antwortet mit einem Fehler → „Beiträge konnten nicht geladen werden”

Mit der echten API sehen wir praktisch immer nur den ersten Zustand. Die anderen beiden lassen sich jedoch mit Mocking zuverlässig herstellen, dazu gleich mehr.

Woher kommen die Daten? Der Netzwerk-Tab

Woran erkennt man, dass Inhalte dynamisch von einer API kommen? Ein Blick in die Entwicklertools zeigt es:

  1. Rechtsklick auf die Seite → Untersuchen
  2. Zum Tab Netzwerk (bzw. Network) wechseln
  3. Dann im Testlab auf den Button „Beiträge laden” klicken, siehe oben
  4. Im Tab Netzwerk den Eintrag posts?_limit=3 anklicken

Im Reiter Header steht die URL des Aufrufs (https://jsonplaceholder.typicode.com/posts?_limit=3), im Reiter Antwort das JSON-Objekt mit den Beiträgen – und genau diese Titel sehen wir auch in der Liste auf der Seite.

Diesen Aufruf fängt Playwright im Test ab und ersetzt die Antwort nun durch eigene Daten.

Wofür braucht man Mocking?

  • Schwer herstellbare Zustände: Eine leere Liste oder ein Serverfehler lassen sich mit einer echten, funktionierenden API kaum zuverlässig provozieren
  • Langsame APIs: Eine gemockte Antwort kommt sofort und macht den Test schneller und stabiler
  • Unzuverlässige Drittanbieter: Wenn eine externe API im Testsystem instabil ist, lässt sie sich gezielt ersetzen, ohne den Rest der Anwendung anzufassen

Hinweis: Mehr zu Mock-Objekten erfährst du übrigens hier.

Der erste Mock in Playwright

Ein Mock wird mit page.route() eingerichtet. Das erste Argument ist die URL (oder ein Muster), die abgefangen werden soll, das zweite eine Callback-Funktion, die festlegt, was stattdessen passiert:

Zwei Dinge sind hier wichtig:

  • Reihenfolge: Die Route muss vor dem Klick auf den Button definiert werden. Der fetch()-Aufruf passiert erst beim Klick – würde man erst danach mocken, wäre der echte Request schon unterwegs.
  • Die Assertion am Ende: click() wartet nur darauf, dass der Klick ausgeführt wurde, nicht darauf, dass die Antwort ankommt und die Liste gerendert wird. Ohne Assertion würde der Test sofort nach dem Klick grün enden, noch bevor überhaupt etwas geprüft wurde. Die Assertion ist also die eigentliche Prüfung, und weil expect(locator) die Bedingung automatisch wiederholt, bis sie erfüllt ist (standardmäßig bis zu 5 Sekunden), wartet Playwright dabei auch gleich auf die gemockte Antwort.

Nach dem erfolgreichen Testlauf zeigt die Liste die drei gemockten Beiträge statt der echten Titel von JSONPlaceholder, nachvollziehbar indem ich ein page.pause() ergänze:

Wildcards statt fester URL

Im Beispiel steht statt der kompletten URL ein Muster mit Wildcard:

'**/posts?_limit=3'

Das ** steht für beliebige Zeichen davor – der Test ist damit unabhängig davon, ob der Aufruf über https://, mit oder ohne www. oder über eine andere Domain-Variante läuft.

Große Antworten in eine JSON-Datei auslagern

Echte API-Antworten sind oft deutlich umfangreicher als in diesem Beispiel. Solche Objekte gehören nicht in den Testcode, sondern in eine eigene Datei, zum Beispiel mock/posts.json:

Den Test dann entsprechend anpassen:

Edge Cases testen: Leere Liste und Serverfehler

Jetzt spielt Mocking seine Stärke aus. Mit einer leeren Antwort prüfen wir den Zustand „keine Beiträge” – ein Zustand, den die echte API in diesem Beispiel praktisch nie liefert:

Und mit einem Statuscode 500 simulieren wir einen Serverfehler, den man mit der funktionierenden echten API überhaupt nicht provozieren könnte:

Nur bestimmte Requests abfangen

Manchmal soll nicht jeder Aufruf an einen Endpunkt gemockt werden – etwa nur GET-Requests, während alle anderen normal durchlaufen. Dafür lässt sich in der Callback-Funktion die Art des Requests prüfen:

Mit route.continue() wird der Request unverändert an den echten Server weitergereicht. Auf die gleiche Weise lässt sich auch nach dem Inhalt des Requests unterscheiden, zum Beispiel über route.request().postData().

Fazit: Mit Augenmaß einsetzen

Mocking ist einfach umzusetzen und sehr wirkungsvoll: Es macht Tests schneller, stabiler und erlaubt Szenarien, die sich mit echten Daten kaum herstellen lassen.

Man sollte es aber nicht übertreiben. Wer zu viele Endpunkte mockt, erhöht zwar die Stabilität der Tests, testet aber nicht mehr die echte Zusammenarbeit von Frontend und Backend – und übersieht so Fehler an genau dieser Schnittstelle.

Sinnvoll ist Mocking vor allem für langsame Endpunkte, für Edge Cases und Fehlerszenarien. Alles andere gehört weiterhin in echte End-to-End-Tests.

Weiterführende Links

Über mich

Dieser Beitrag wurde veröffentlicht .