Zum Inhalt springen

Aufgabe 13 - Jahresprojekt Sprint 4 - Testebenen und Testpyramide

Zu Zen-Modus wechseln
  • Du ordnest Tests den Ebenen Unit, Integration und End-to-End zu, danach, wie viel vom System mitläuft.
  • Du isolierst Fachlogik mit einem handgeschriebenen Stub.
  • Du planst Sprint 4, den letzten Sprint vor der Abnahme.
  • Du zeichnest die Ist-Pyramide deines Projekts, benennst ihre Form und sicherst die Fachlogik mit Unit-Tests und einem Testdaten-Builder ab.
  • Du unterscheidest Stub und Mock und machst Abhängigkeiten von Uhr und Zufall austauschbar.

Erste Woche von Sprint 4, des letzten Sprints vor der Abnahme. Bisher habt ihr getestet, was ihr aus der 4. Klasse kennt. Kapitel 19 gibt dem eine Ordnung: drei Testebenen, die Testpyramide (viele schnelle Unit-Tests, einige Integrationstests, wenige End-to-End-Tests) und Test-Doubles, mit denen ihr eure Fachlogik ohne Datenbank, Netzwerk und Uhr prüft. Die Vorarbeit habt ihr schon: Seit Aufgabe 09 hängt eure Fachlogik an einem Interface.

Die Kata: Zeugnisdruck der Musikschule (alle Daten erfunden). Der Startcode:

export interface Student {
id: number;
name: string;
lessons: number;
}
export interface StudentRepository {
findById(id: number): Student | undefined;
listAll(): Student[];
}
export class CertificateService {
constructor(private readonly repository: StudentRepository) {}
headline(id: number): string {
const student = this.repository.findById(id);
if (student === undefined) throw new Error(`no student ${id}`);
return student.lessons >= 30 ? `${student.name}: mit Auszeichnung` : student.name;
}
}

Sechs Tests aus einem anderen Projekt, nur beschrieben:

  1. Ein Test ruft eine reine Funktion formatDuration(125) auf und erwartet "2:05".
  2. Ein Test startet den Browser, meldet sich an, lädt eine Datei hoch und prüft, dass sie in der Liste erscheint.
  3. Ein Test schickt eine HTTP-Anfrage an die laufende API mit echter Testdatenbank und prüft den Statuscode.
  4. Ein Test prüft eine Rabattregel mit einem Stub als Repository.
  5. Ein Test speichert einen Datensatz über das echte Repository in eine Testdatenbank und liest ihn wieder.
  6. Ein Test prüft mit vi.fn(), dass nach einer Bestellung genau eine Bestätigungsmail verschickt wird, der Mailversand ist ersetzt.

Dafür brauchst du:

  • Kapitel 19 Teststrategien I (Testebenen, Testpyramide und Eistüte, Werkzeuge, Stub, Mock und Fake, Testdaten-Builder, kein Zufall im Test).
  • Vitest (npm install --save-dev vitest, Ausführen mit npx vitest run) oder den Testrunner, den euer Projekt seit Aufgabe 03 verwendet.

Projektordner anlegen siehe https://qiz.at/projektordner

  • Lies vorher kurz https://qiz.at/assignmentsabgabe durch.
  • Nur vollständige Abgaben (siehe https://qiz.at/rules) können positiv bewertet werden.
  • Abgabe- und Testdetails siehe https://qiz.at/assignmentsabgabe
  • Abgegeben wird dein Projektordner mit der Kata (Code, Tests und README.md) und den Links auf Issues, Merge Requests und docs/test-pyramid.md im Jahresprojekt-Repository. Bezeichner und Kommentare im Code sind Englisch.
  • Wer was beigetragen hat, zeigen Board, Merge Requests und /spend-Einträge (Kapitel 07).
  • Kata: Ordne die sechs beschriebenen Tests je einer Ebene zu und nenne in einem Satz, was dabei mitläuft. Schreibe für CertificateService einen handgeschriebenen StubRepository (feste Antworten, kein Speichern) und drei Tests ohne echte Datenquelle: Normalfall, Auszeichnung genau an der Grenze von 30 Stunden, unbekannte ID.
  • Planning von Sprint 4: Retro-Maßnahme aus Sprint 3 prüfen, Milestone Sprint 4 mit Review-Termin in Woche drei, Sprint-Ziel als ein Satz. Plant bewusst Zeit für Tests und die Vorbereitung der Abnahme ein: Was im Review von Sprint 4 nicht vorführbar ist, kommt nicht in die Abnahme.

Tipp: Die Ebene eines Tests bestimmst du danach, wie viel vom System mitläuft, nicht nach dem Dateinamen. Ein Stub muss das ganze Interface erfüllen; Methoden, die der Test nicht braucht, liefern einen einfachen Wert.

Vollständig, wenn:

  • alle sechs Tests richtig eingeordnet und begründet sind (Unit: 1, 4, 6; Integration: 3, 5; End-to-End: 2),
  • die drei Stub-Tests grün sind, ohne echte Datenquelle auskommen und der Fehlerfall die Meldung prüft,
  • die Retro-Maßnahme überprüft, der Milestone Sprint 4 angelegt und das Sprint-Ziel ein Satz über einen Zustand des Produkts ist.

Wie unter Allgemein.

Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.

Erweitere (siehe Erweitern in https://qiz.at/rules) den vollständigen Teil der vorherigen Stufe dieser Datei (ändere oder lösche nur, was für diese Aufgabe unbedingt notwendig ist):

  • Ist-Pyramide: Zählt alle Tests eures Projekts je Ebene, zeichnet die tatsächliche Pyramide mit Anzahl je Ebene in docs/test-pyramid.md und benennt ihre Form mit dem Fachbegriff. Eine leere Ebene ist ein Befund.
  • Unit-Tests der Fachlogik: Legt ein Issue an und schreibt in einem Merge Request Unit-Tests für die wichtigste Regel eurer Fachlogik (Normalfall, Grenzwert, abgelehnter Fall). Das Repository ersetzt ihr durch einen Stub oder durch eure Implementierung im Arbeitsspeicher aus Aufgabe 09 (Fake).
  • Baut dafür einen Testdaten-Builder aX(overrides) für euer wichtigstes Fachobjekt mit gültigen, festen Standardwerten und verwendet ihn in allen neuen Tests.
  • Stellt sicher, dass die Tests in der Pipeline laufen und einen Merge blockieren, wenn sie rot sind.

Tipp: Ein Builder muss gültige Objekte liefern, sonst scheitern Tests aus dem falschen Grund. Keine Zufallswerte und keine aktuelle Uhrzeit als Standardwert.

Vollständig, wenn:

  • docs/test-pyramid.md die Zählung je Ebene, ein Diagramm und die benannte Form enthält,
  • mindestens drei neue Unit-Tests die wichtigste Regel ohne echte Infrastruktur prüfen und grün sind,
  • der Builder feste, gültige Standardwerte liefert und von allen neuen Tests verwendet wird,
  • die Pipeline die Tests ausführt.

Wie unter Allgemein.

Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.

Erweitere (siehe Erweitern in https://qiz.at/rules) den vollständigen Teil der vorherigen Stufe dieser Datei (ändere oder lösche nur, was für diese Aufgabe unbedingt notwendig ist):

  • Suche in eurem Projekt eine Stelle, an der der Aufruf selbst das Verhalten ist (zum Beispiel: genau eine Benachrichtigung wird verschickt, ein Eintrag wird genau einmal gespeichert). Teste sie mit einem Mock (vi.fn(), toHaveBeenCalledTimes, toHaveBeenCalledWith) und eine andere Stelle mit einem Stub. Begründe im README.md in zwei Sätzen, warum hier jeweils das passende Double gewählt ist.
  • Ergänze einen Integrationstest, der Fachlogik und echten Datenzugriff (Testdatenbank oder Testdatei) zusammen prüft, und nenne einen Fehler, den nur dieser Test findet.

Tipp: Kapitel 19 warnt: Nicht alles mocken. Eigene Fachlogik testest du mit echten Objekten, ersetzt werden nur die Ränder.

Vollständig, wenn:

  • Mock- und Stub-Test Verschiedenes prüfen (Interaktion gegen Ergebnis) und die Wahl begründet ist,
  • der Integrationstest grün ist und ein Fehlertyp genannt ist, den die Unit-Tests prinzipiell nicht finden.

Wie unter Allgemein.

Für alle, die in der Einheit mit den Schritten oben fertig sind bzw. optional (= freiwillig), wenn du in der Einheit nicht fertig wirst.

Erweitere (siehe Erweitern in https://qiz.at/rules) den vollständigen Teil der vorherigen Stufe dieser Datei (ändere oder lösche nur, was für diese Aufgabe unbedingt notwendig ist):

  • Sucht in Code und Tests eures Projekts jede Abhängigkeit von der aktuellen Uhrzeit oder von Zufall. Macht die wichtigste davon zu einer hereingereichten Abhängigkeit (Uhr als Parameter oder Konstruktorargument) und schreibt einen Test mit fester Uhr, der ohne die Änderung zu einer bestimmten Tageszeit rot werden könnte. Erklärt, wann.
  • Zeichnet in docs/test-pyramid.md neben die Ist-Pyramide die Soll-Pyramide für das Projektende und begründet in drei Sätzen mit Laufzeit und Aussagekraft der Ebenen, warum die Pyramidenform wirtschaftlich und nicht bloß Konvention ist.

Tipp: Das Beispiel aus Kapitel 19 mit dem Test um Mitternacht zeigt, wie ein zeitabhängiger Test ohne Codeänderung rot wird.

Vollständig, wenn:

  • die Abhängigkeit von Uhr oder Zufall hereingereicht ist, der Test mit fester Uhr grün ist und der kritische Zeitpunkt erklärt ist,
  • Ist- und Soll-Pyramide nebeneinander stehen und die Begründung Laufzeit und Aussagekraft nennt.

Wie unter Allgemein.

Durchschnittlich bis Wesentlich_vollständig: ca. 70 min (5 min Board-Check, 20 min Kata, 15 min Planning, 30 min Pyramide und Unit-Tests im Projekt)

GAM

CC-BY-SA

https://qiz.at/rules