Modulseite

Lektion 1 von 9

Warum testen? Fehler, Teststufen und die Testpyramide

Du unterscheidest Fehlhandlung, Fehlerzustand und Fehlerwirkung, ordnest Tests den Teststufen zu, begründest die Testpyramide und findest mit deinem ersten automatisierten Test einen echten Rabattfehler.

ca. 40 Min.0/6 Checks gelöst

Worum es geht

Montagmorgen bei der Eventa Ticketing AG in Winterthur. Im Support-Postfach liegen 63 neue Nachrichten, fast alle zum selben Thema: «Wir sind zu zehnt und haben den vollen Preis bezahlt. Auf eurer Seite steht doch: Gruppen ab 10 Personen erhalten 15 Prozent!» Eine Schulklasse, ein Turnverein, eine Firmenfeier. Für jede Bestellung muss jemand nachrechnen, Geld zurückbuchen und sich entschuldigen.

Der Fehler steckte in einer einzigen Zeile Code. Ein automatisierter Test, der weniger als eine Sekunde läuft, hätte ihn vor dem Release gefunden.

Nora ist im 3. Lehrjahr als Informatikerin Applikationsentwicklung bei Eventa. Ihr Berufsbildner gibt ihr den Auftrag, das Testen für das nächste Release mit Sitzplatzwahl neu aufzuziehen. In diesem Kurs begleitest du sie dabei. In dieser ersten Lektion klärst du die Grundbegriffe: was Testen leisten kann, welche Teststufen es gibt und warum die Testpyramide so aussieht, wie sie aussieht. Am Ende schreibst du deinen ersten automatisierten Test und findest damit genau den Fehler, der Eventa so viel Ärger gemacht hat.

Was Testen leistet und was nicht

Testen heisst: Du führst Software unter kontrollierten Bedingungen aus und vergleichst das tatsächliche Ergebnis mit dem erwarteten. Weicht beides ab, hast du einen Fehler gefunden. Dafür brauchst du immer zwei Dinge: eine Eingabe und eine klare Erwartung. «Mal schauen, ob es läuft» ist kein Test, weil die Erwartung fehlt.

Das Wort «Fehler» ist im Alltag ungenau. In der Testwelt unterscheidet man drei Stufen:

BegriffBedeutungBeispiel bei Eventa
FehlhandlungEin Mensch macht einen Denk- oder TippfehlerDie Entwicklerin liest «ab 10» als «mehr als 10»
Fehlerzustand (Defekt)Der falsche Code steht im Programmif (anzahl > 10) statt if (anzahl >= 10)
FehlerwirkungDas Programm verhält sich sichtbar falschZehn Personen bezahlen den vollen Preis

Tests decken Fehlerwirkungen auf. Die Ursache, also den Fehlerzustand im Code, suchst du danach beim Debugging. Testen und Debugging sind zwei verschiedene Tätigkeiten: Das eine zeigt, dass etwas falsch ist, das andere findet, wo und warum.

Ein paar Grundsätze helfen dir, realistische Erwartungen zu haben:

  • Tests zeigen Fehler, sie beweisen keine Fehlerfreiheit. 200 grüne Tests heissen nur: In diesen 200 Situationen stimmt das Verhalten.
  • Vollständiges Testen ist unmöglich. Schon ein Formular mit Alter (0 bis 120), Anzahl Tickets (1 bis 50) und Wochentag hat 121 × 50 × 7 = 42'350 Kombinationen. Du musst also klug auswählen. Wie, lernst du in den Lektionen 3 und 4.
  • Früh testen spart Geld. Ein Fehler, den du beim Programmieren findest, kostet Minuten. Derselbe Fehler in Produktion kostet Rückerstattungen, Supportstunden und Vertrauen.
  • Fehler häufen sich. Meist steckt ein grosser Teil der Fehler in wenigen Komponenten, oft dort, wo die Logik kompliziert ist oder häufig geändert wird. Dort lohnt sich genaues Hinsehen.
  • Tests nutzen sich ab. Wer immer dieselben Tests wiederholt, findet irgendwann keine neuen Fehler mehr. Testfälle müssen mit dem Code mitwachsen.
Check 1 · Mehrere AntwortenEinstieg

Welche Aussagen über das Testen von Software treffen zu?

Wähle alle zutreffenden Antworten.

Check 2 · ReihenfolgeEinstieg

Bring die Kette in die richtige Reihenfolge: Wie wird aus einem Denkfehler eine Reklamation, und wie wird er behoben?

  1. 1

    Im Code steht if (anzahl > 10) (Fehlerzustand).

  2. 2

    Die Entwicklerin liest «ab 10 Personen» als «mehr als 10 Personen» (Fehlhandlung).

  3. 3

    Eine Gruppe mit genau 10 Personen bezahlt den vollen Preis (Fehlerwirkung).

  4. 4

    Beim Debugging findet das Team die falsche Bedingung und korrigiert sie.

  5. 5

    Der Turnverein beschwert sich beim Support.

Teststufen: vom Baustein bis zur Abnahme

Software besteht aus vielen Teilen, und jeder Teil kann auf seine Art kaputt sein. Darum testet man auf mehreren Teststufen. Stell dir den Bau eines Velos vor: Zuerst prüfst du einzelne Teile (hält die Bremse?), dann, ob die Teile zusammenpassen (greift die Kette ins Ritzel?), dann das ganze Velo auf einer Probefahrt, und zum Schluss entscheidet die Kundin, ob es ihr passt.

TeststufeWas wird geprüftBeispiel bei EventaTypische Werkzeuge
Unit-Test (Komponententest)eine Funktion oder Klasse, isoliertgruppenpreis(10, 4500) liefert 38250Vitest, Jest, JUnit, xUnit
IntegrationstestZusammenspiel von Komponenten, z.B. Service mit Datenbank oder APIReservation wird korrekt in PostgreSQL gespeichertTestcontainers, Supertest, Postman
Systemtestdas ganze System aus Sicht der BenutzendenKauf vom Saalplan bis zur BestätigungsmailPlaywright, Cypress, manuelle Testfälle
Abnahmetesterfüllt das System die Anforderungen der Auftraggeber?Product Owner prüft die Sitzplatzwahl vor dem Go-liveAbnahmeprotokoll, Testszenarien

Quer zu den Stufen gibt es Testarten. Funktionale Tests prüfen, was das System tut (stimmt der Preis?). Nicht-funktionale Tests prüfen, wie gut es das tut: Lasttests (hält der Shop 5000 gleichzeitige Käufe beim Vorverkaufsstart aus?), Sicherheitstests, Usability-Tests. Regressionstests wiederholen bestehende Tests nach einer Änderung, um sicherzustellen, dass nichts kaputtgegangen ist, was vorher funktionierte.

Check 3 · ZuordnenEinstieg

Ordne jedem Test bei Eventa die passende Teststufe zu.

Die Testpyramide

Wie viele Tests gehören auf welche Stufe? Die bekannteste Antwort ist die Testpyramide, die auf Mike Cohn zurückgeht: viele Unit-Tests als breites Fundament, weniger Integrationstests in der Mitte und nur wenige End-to-End-Tests an der Spitze.

Der Grund ist nicht Geschmack, sondern die Natur der Tests:

EigenschaftUnit-TestIntegrationstestEnd-to-End-Test
LaufzeitMillisekundenSekundenoft 10 Sekunden und mehr
Stabilitätsehr hochhochanfällig für Timing und Testdaten
Fehlersuchezeigt direkt die Funktiongrenzt auf eine Schnittstelle ein«irgendwo im Ablauf»
Wartungsaufwandgeringmittelhoch

Ein roter Unit-Test sagt dir: «gruppenpreis rechnet bei 10 Personen falsch.» Ein roter End-to-End-Test sagt dir: «Der Kauf hat nicht geklappt.» Ob das am Preis, an der Datenbank, an einer Animation oder am Testserver lag, musst du dann erst herausfinden.

Trotzdem braucht es die Spitze: Nur ein End-to-End-Test merkt, wenn alle Teile einzeln funktionieren, aber nicht zusammen. Für Eventa plant Nora rund 180 Unit-Tests für Preise, Rabatte und Regeln, etwa 25 Integrationstests für Reservation, Zahlung und Datenbank und drei End-to-End-Tests für die Kernabläufe Kaufen, Stornieren und Anmelden.

Check 4 · Eine AntwortEinstieg

Nora plant die automatisierten Tests für den Ticketshop. Welche Verteilung entspricht der Testpyramide?

Schritt für Schritt: Der erste Test findet den Rabattfehler

Schritt 1: Die Anforderung lesen. «Gruppen ab 10 Personen erhalten 15 Prozent Rabatt auf den Gesamtpreis.» Eventa rechnet Beträge in Rappen, damit keine Rundungsfehler mit Kommazahlen entstehen: CHF 45.00 = 4500.

Schritt 2: Den Code ansehen. So stand die Funktion im letzten Release:

JavaScript
// src/preis.js
export function gruppenpreis(anzahl, einzelpreisRappen) {
  const total = anzahl * einzelpreisRappen;
  if (anzahl > 10) {
    return Math.round(total * 0.85);   // 15 Prozent Rabatt
  }
  return total;
}

Schritt 3: Testfälle mit Erwartung festlegen. Bevor du den Test programmierst, rechnest du von Hand aus, was herauskommen muss. Wo liegt das Risiko? An der Grenze bei 10.

FallAnzahlRechnungerwartet (Rappen)
knapp darunter99 × 450040500
genau auf der Grenze1045000 × 0.8538250
knapp darüber1149500 × 0.8542075

Schritt 4: Den Test schreiben. Vitest installierst du mit npm install -D vitest. Testdateien enden auf .test.js und liegen neben dem Code oder in einem eigenen Ordner.

JavaScript
// src/preis.test.js
import { describe, it, expect } from "vitest";
import { gruppenpreis } from "./preis.js";

describe("gruppenpreis", () => {
  it("gibt 9 Personen keinen Rabatt", () => {
    expect(gruppenpreis(9, 4500)).toBe(40500);
  });

  it("gibt genau 10 Personen 15 Prozent Rabatt", () => {
    expect(gruppenpreis(10, 4500)).toBe(38250);
  });

  it("gibt 11 Personen 15 Prozent Rabatt", () => {
    expect(gruppenpreis(11, 4500)).toBe(42075);
  });
});

describe fasst zusammengehörige Tests zusammen, it ist ein einzelner Testfall, und expect(...).toBe(...) vergleicht das tatsächliche mit dem erwarteten Ergebnis.

Schritt 5: Ausführen. Mit npx vitest run laufen alle Tests einmal durch (ohne run startet Vitest im Beobachtungsmodus und wiederholt die Tests bei jeder Änderung):

Text
 FAIL  src/preis.test.js > gruppenpreis > gibt genau 10 Personen 15 Prozent Rabatt
AssertionError: expected 45000 to be 38250 // Object.is equality

 Test Files  1 failed (1)
      Tests  1 failed | 2 passed (3)

Der Test hat genau die Fehlerwirkung gefunden, über die sich die Kundschaft beschwert hat: Zehn Personen bezahlen 45000 statt 38250 Rappen.

Schritt 6: Korrigieren und wiederholen. Aus anzahl > 10 wird anzahl >= 10. Nach dem nächsten npx vitest run sind alle drei Tests grün.

Schritt 7: Den Test behalten. Der Test bleibt im Projekt und läuft ab jetzt bei jeder Änderung mit. Wer die Rabattlogik später umbaut, erfährt sofort, wenn die Grenze wieder kippt. Genau das ist ein Regressionstest.

Jetzt bist du dran. Im ersten Labor reparierst du den Preisrechner aus dem letzten Release, der sogar zwei Fehler enthält. Im zweiten schreibst du selbst Tests, die fehlerhafte Versionen einer Preisfunktion entlarven.

Check 5 · Code-LaborEinstieg

Code-Labor: Die Tests sind rot. Das ist der Preisrechner aus dem letzten Release von Eventa, der die Kundschaft verärgert hat. Die Regel lautet: Gruppen ab 10 Personen erhalten 15 Prozent Rabatt auf den Gesamtpreis. Klick auf «Ausführen», lies die Meldungen der roten Tests und korrigiere die Funktion, bis alle Tests grün sind. Beträge sind in Rappen (CHF 45.00 = 4500).

Code-Labor · JavaScript
Strg + Enter
Check 6 · Code-LaborFortgeschritten

Code-Labor: Dein erster Test. Jetzt drehst du den Spiess um und schreibst selbst die Tests. Ergänze pruefe() so, dass deine Tests eine korrekte Version von eintrittspreis(alter) bestehen lassen und vier absichtlich fehlerhafte Versionen erwischen.

Die Regel: Ein Alter unter 0 ist ungültig (Fehler). Kinder unter 6 Jahren sind gratis, 6 bis 15 Jahre kosten CHF 25, ab 16 Jahren CHF 45. Beträge in Rappen.

Code-Labor · JavaScript
Strg + Enter

Typische Fehler

  1. Test ohne Erwartung. «Ich habe es ausprobiert, es lief» ist kein Test. Ohne vorher festgelegtes Ergebnis kannst du nicht entscheiden, ob 45000 richtig oder falsch ist.
  2. Den erwarteten Wert aus dem Programm abschreiben. Wer das Ergebnis einmal ausgibt und dann in den Test kopiert, zementiert den Fehler. Die Erwartung kommt aus der Anforderung, von Hand gerechnet.
  3. Nur den Normalfall testen. Ein Test mit 20 Personen wäre grün gewesen. Fehler sitzen an Grenzen und bei ungewöhnlichen Eingaben.
  4. Alles über die Oberfläche testen. Wer jede Rabattregel durch Klicken im Browser prüft, braucht Stunden und findet den Fehler nur, wenn er zufällig genau 10 Tickets wählt.
  5. «Grün» mit «fehlerfrei» verwechseln. Grüne Tests sagen nur etwas über die geprüften Fälle aus.

Zusammenfassung

  • Testen heisst: ausführen und das tatsächliche mit dem erwarteten Ergebnis vergleichen. Ohne Erwartung kein Test.
  • Eine Fehlhandlung (Mensch) führt zu einem Fehlerzustand (Code), der eine Fehlerwirkung (sichtbares Fehlverhalten) auslöst. Tests finden Wirkungen, Debugging findet Ursachen.
  • Vollständiges Testen ist unmöglich, deshalb wählst du Testfälle gezielt aus.
  • Teststufen: Unit, Integration, System, Abnahme. Testarten wie Last- oder Regressionstests liegen quer dazu.
  • Die Testpyramide: viele schnelle Unit-Tests, weniger Integrationstests, wenige End-to-End-Tests.
  • Ein automatisierter Test, der einmal einen Fehler gefunden hat, bleibt als Regressionstest im Projekt.