TEKO Schweizerische FachschuleEAI IntegrationslaborTheorie 7 · Tests & Observability
TestbefehleLive prüfen

Theorie 07 · Nachweis

„Es läuft“ ist
kein Testergebnis

Tests zeigen, ob sich ein System unter definierten Bedingungen erwartungsgemäß verhält. Observability hilft, unbekannte Fehler zu untersuchen. Beides ergänzt sich – und beides braucht konkrete Identitäten, Messpunkte und erwartete Resultate.

ca. 14 MinutenTestpyramideContractFailure InjectionLogs · Metriken · Traces
1 · Testdenken

Ein Test braucht Ausgangslage, Aktion und Erwartung

„Ich habe auf den Button geklickt und nichts Rotes gesehen“ ist eine Beobachtung, aber kein belastbarer Test. Ein reproduzierbarer Test beschreibt zuerst den Startzustand, führt eine klar definierte Aktion aus und prüft anschließend sichtbare Wirkungen. Bei Integrationen gehören dazu nicht nur HTTP-Statuscodes, sondern auch Zielobjekte, Queue-Zustände, Duplikate und Protokolle.

Ein guter Test scheitert verständlich. Er sagt nicht nur „false“, sondern beispielsweise: „Erwartet Jobstatus completed nach höchstens 10 Sekunden; erhalten retrying mit Versuch 3 und Fehlerklasse upstream_unavailable.“ Dadurch wird der Test zugleich zu einer ausführbaren Spezifikation.

Metapher: Feueralarm-ProbeSirene, Fluchtweg und Sammelplatz werden nach einem vorbereiteten Szenario geprüft. Nicht nur der Melder, sondern der ganze Ablauf zählt.
Wo die Metapher endetSoftwaretests können sehr häufig und automatisiert laufen, bilden aber nie jede reale Kombination aus Daten, Last, Zeit und externem Verhalten ab.
Entscheidungsregel: Formuliere vor dem Test mindestens eine beobachtbare Erwartung und ein Zeitlimit. Ohne Oracle – die Regel, was korrekt ist – kann Automatisierung nur ausführen, nicht bewerten.
2 · Testebenen

Viele schnelle Tests unten, wenige realistische oben

Unit-Tests prüfen kleine Logikeinheiten ohne echte Nachbarsysteme. Contract-Tests prüfen, ob Request und Response einem vereinbarten Schema und Verhalten entsprechen. Integrationstests starten echte Komponenten wie HTTP-Server, SQLite oder Orthanc. End-to-End-Tests gehen durch das öffentlich sichtbare Gateway. Resilienztests verändern gezielt die Umgebung.

Testpyramide für das IntegrationslaborEine Pyramide mit breiter Basis aus Unit-Tests, darüber Contract- und Integrationstests, schmalen End-to-End-Tests und seitlich Störungstests.Unit: Validierung · Statusmaschine · BackoffContract: JSON · StatuscodesIntegration: HTTP · DB · OrthancE2EStörungstests• Ziel nicht erreichbar• Timeout• ungültiges Event• Doppelzustellung• Neustart
Die Form ist eine Heuristik, keine feste Mengenquote. Kritische Integrationsverträge und Fehlerpfade brauchen überproportional viel Aufmerksamkeit.
EbeneBeispiel im Spital-LabTypische Lücke
UnitEvent ohne StudyInstanceUID wird abgelehntKein echter Netzwerk-/Serialisierungseffekt
ContractPOST /api/spital/jobs liefert 202 und Job-URLConsumer kann semantisch trotzdem falsch handeln
IntegrationWorker liest internen Orthanc-StatusReverse Proxy und TLS fehlen
End-to-EndÖffentliche Domain → Gateway → API → JobTeurer und empfindlicher, Diagnose schwieriger
ResilienzOrthanc-Ausfall erzeugt Retry und RecoveryStörung kann unrealistisch simuliert sein
3 · Vertrag

Syntax, Semantik und Verhalten testen

Ein JSON-Schema kann Typen, Pflichtfelder und erlaubte Werte prüfen. Das ist notwendig, aber nicht ausreichend. Eine syntaktisch gültige Modalität XX kann fachlich unzulässig sein. Ein korrektes Datum kann in der Vergangenheit liegen. Contract-Tests verbinden deshalb Struktur mit beispielhaftem Verhalten: gültige Anfrage, fehlendes Feld, falscher Typ, unbekannter Wert, zu großer Body und unerlaubte Methode.

Auch Fehler sind Teil des Vertrags. Eine API sollte vorhersehbare Statuscodes und maschinenlesbare Fehler liefern. 400 steht für eine ungültige Anfrage, 404 für eine nicht gefundene Ressource, 409 für einen Konflikt und 429 für ein Limit. Ein pauschales 500 für jeden Fall erschwert Clients, Betrieb und Unterricht.

# Happy Path
curl -i -X POST https://teko.algorithma.app/api/spital/jobs \
  -H 'Content-Type: application/json' \
  -d '{"studyInstanceUid":"1.2.826.0.1.3680043.10.543.42",
       "accessionNumber":"DEMO-0042","modality":"CT"}'

# Negativtest: Patientendaten werden nicht akzeptiert
curl -i -X POST https://teko.algorithma.app/api/spital/jobs \
  -H 'Content-Type: application/json' \
  -d '{"patientName":"Nicht erlaubt"}'
Gegenbeispiel: Der Test prüft nur, dass irgendein 2xx zurückkommt. Die Response enthält aber keine Job-ID, der Job wird nie verarbeitet, und dieselbe Anfrage erzeugt bei Wiederholung drei Datensätze. Der Vertrag war zu schwach.
4 · Zeit

Asynchrone Tests warten auf Zustände, nicht auf Glück

Ein asynchroner POST antwortet häufig mit 202 Accepted. Das bedeutet: Die Anfrage wurde angenommen, nicht abgeschlossen. Die Response liefert eine Job-ID oder einen Location-Header. Der Test fragt den Status wiederholt ab, bis ein Endzustand erreicht ist oder ein festes Zeitlimit abläuft.

Ein statisches sleep 10 macht Tests langsam und unzuverlässig. Besser ist Polling mit kurzem Intervall, globalem Timeout und Ausgabe des letzten Zustands. Der Test muss mögliche Übergänge kennen, etwa queued → processing → completed oder queued → retrying → dead-letter. Unerlaubte Übergänge sind selbst Fehler.

Idempotenz wird mit zwei gleichen Requests geprüft. Beide dürfen dieselbe Jobrepräsentation liefern oder der zweite darf einen klaren Konflikt melden; entscheidend ist, dass nur eine fachliche Zielwirkung entsteht. Zusätzlich wird ein gleicher fachlicher Schlüssel mit einer neuen Event-ID getestet: Je nach Vertrag kann das ein neues Ereignis, aber weiterhin dieselbe Studie sein.

Entscheidungsregel: Ein Async-Test ist erst fertig, wenn ein Endzustand samt fachlicher Wirkung geprüft wurde. 202 allein beweist nur Annahme.
5 · Resilienz

Fehler werden absichtlich erzeugt

Resilienz lässt sich nicht aus dem Quellcode ablesen. Das Zielsystem wird gestoppt oder ein kontrollierter Fehlerpfad aktiviert. Dann prüft der Test Versuchszähler, Backoff, Status, Logkontext und Wiederaufnahme. Nach dem Neustart muss der Job ohne manuellen Datenverlust fertig werden.

Technische und fachliche Fehler werden getrennt: Ein unerreichbares Orthanc ist wahrscheinlich temporär und retrybar. Eine ungültige StudyInstanceUID oder nicht erlaubte Modalität wird durch zehn Wiederholungen nicht gültig. Sie gehört in eine Quarantäne/DLQ mit erklärbarem Grund. Ein Replay darf erst nach Korrektur oder bewusster Freigabe erfolgen.

  • Timeout nach Wirkung: Ziel hat gespeichert, Antwort ging verloren – Deduplikation prüfen.
  • Neustart während Verarbeitung: Job bleibt dauerhaft nachvollziehbar und wird nicht vergessen.
  • Queue-Rückstau: Annahme wird begrenzt; Speicher wächst nicht unendlich.
  • Poison Message: Ein ungültiges Event blockiert nicht alle folgenden.
  • Doppelzustellung: Ein fachlicher Effekt bleibt einmalig.
6 · Beobachtbarkeit

Logs erzählen Ereignisse, Metriken zeigen Muster, Traces verbinden Wege

Monitoring beantwortet bekannte Fragen mit vorbereiteten Signalen: Ist die Fehlerrate erhöht? Wächst die Queue? Observability zielt darauf, aus den erzeugten Signalen auch unbekannte Fragen untersuchen zu können. Drei klassische Signale sind Logs, Metriken und Traces.

Strukturierte Logs enthalten Zeitpunkt, Level, Dienst, Eventname, Job-ID, Correlation-ID, Versuch und Fehlerklasse. Metriken zählen Jobs, Fehler, Retry, DLQ und Laufzeiten. Ein Trace zeigt zusammengehörige Spans über Gateway, API, Worker und Orthanc. Für das kleine Labor übernimmt die Correlation-ID einen Teil dieser Verbindung; sie wird in Response und Jobstatus sichtbar.

SignalStärkeBeispielfrage
LogDetail eines EreignissesWarum scheiterte corr-imaging-0042 im Versuch 2?
MetrikAggregation über ZeitWie viele Jobs gingen in den letzten 15 Minuten in Retry?
TraceWeg und Dauer über DiensteWelcher Hop verbrauchte das Latenzbudget?

Mehr Daten sind nicht automatisch besser. Patientennamen, komplette Payloads oder Secrets gehören nicht in Logs. Hohe Kardinalität wie eine eigene Metrikserie pro Study UID kann Metriksysteme überlasten. Correlation-IDs passen in Logs und Traces, nicht zwingend als Metriklabel.

7 · Dokumentation

Ein Testprotokoll macht Ergebnisse prüfbar

Für Unterricht und Projektprüfung reicht ein Screenshot ohne Kontext nicht. Ein kurzes Protokoll nennt Version/Commit, Umgebung, Zeitpunkt, Befehl, erwartetes Ergebnis, tatsächliches Ergebnis und Beleg. Bei Abweichung folgt eine Interpretation, kein nachträgliches Umschreiben der Erwartung.

Test-ID: E2E-ASYNC-03
Umgebung: lokal, Compose Release 2026.08
Startzustand: alle Healthchecks grün, keine Job-ID vorhanden
Aktion: POST synthetische CT-Studie DEMO-0042
Erwartung: 202; Endzustand completed < 10 s; attemptCount = 1
Ergebnis: erfüllt; Job job-…; correlationId corr-…
Beleg: curl-Output + API-Logzeilen + Orthanc-Health

Kontrollfragen

  1. Warum beweist ein 202 nicht die erfolgreiche Verarbeitung?
  2. Welche Fehlerfälle gehören in einen Contract-Test?
  3. Wie testest du Idempotenz fachlich statt nur technisch?
  4. Wann hilft eine Correlation-ID, wann reicht sie nicht?
  5. Welche Informationen müssen aus Gesundheitsdaten-Logs entfernt bleiben?
Im Projekt enthalten
Der Stack besitzt automatisierte API-, Async-, Fehler- und Sicherheits-Smoke-Tests. Die genauen lokalen und öffentlichen Befehle stehen in der Docker-Anleitung.