Schulung · Vertiefung
Zeit und Tokens sparen mit PHPUnit
Testsuites messen, beschleunigen und für Coding Agents aufbereiten
- Umfang 6 Sitzungen à 2 Stunden
- Format Live über Zoom
- Sprache Deutsch
- Preis pro Person 1.199 €
Worum es geht
Langsame Tests sind kein Schicksal, sondern ein Fehler. Eine Suite, die Minuten braucht, läuft seltener, als sie sollte. Fehler fallen später auf, und das Vertrauen in die Tests sinkt.
In dieser Schulung misst du, wo deine Testsuite ihre Zeit verbringt, und arbeitest dich durch die Stellschrauben: Konfiguration, Testdesign, Testauswahl, Parallelisierung. Jede Stufe wird billiger und wirksamer, wenn die vorherige erledigt ist. Dabei lernst du die neuen Möglichkeiten des Test-Runners von PHPUnit kennen: Test-Index-Cache, Test Impact Analysis, #[Repeat], #[Retry] und --parallel. Du erfährst auch, was sie kosten und was sie bewusst nicht tun.
Ein Coding Agent führt deine Tests noch häufiger aus als du: vor einer Änderung, nach ihr und nach jedem Reparaturversuch. Jede Ausgabe landet in seinem Kontextfenster, kostet Tokens und verdrängt dort Code und Aufgabe. Die Standardausgabe von PHPUnit ist für einen Menschen gemacht, der überfliegt, was er nicht braucht. Ein Agent liest jedes Zeichen. Du richtest PHPUnit für diesen Leser ein, und zwar so, dass es nicht davon abhängt, ob der Agent sich daran erinnert.
So arbeitest du
Die ersten vier Sitzungen folgen einer Formel: Feedbackzeit ≈ Overhead + (Anzahl ausgeführter Tests × Kosten pro Test) ÷ Parallelität. Jede dieser Sitzungen bearbeitet einen Term, an einem Übungsprojekt, das absichtlich langsam ist und für jeden Term eingebaute Probleme mitbringt. Eine Messreihe zeigt, was jede Maßnahme bringt.
In den Sitzungen 5 und 6 wechselt der Leser: Statt eines Menschen, der auf die Suite wartet, liest ein Agent ihre Ausgabe. Was du dort über PHPUnit lernst, gilt für jeden Coding Agent. Wie du es im Projekt verankerst, siehst du an Claude Code und Junie, auf der Ebene der drei Mechanismen Anweisung, Umgebung und Leitplanke, denn agentenspezifische Details ändern sich schnell. Jede Sitzung besteht aus Vorführung, Übung und Diskussion, ohne Folien.
Ablauf
-
Sitzung 1: Messen und Konfigurieren (Overhead)
Wo geht die Zeit hin, und woher weißt du das?
- Was langsame Tests kosten: ein Rechenbeispiel, Flow, TDD und das Vertrauen in die Suite
- Die Form und Größe von Tests: Funktion, Größe und Implementierung, und die Testpyramide als Performance-Budget in Millisekunden, Sekunden und Zehntelminuten
- Messen statt raten:
--log-otrmit phpunit-otr-report,--order-by=duration-descendingmitrecordTestRunHistory, bei Bedarf Profiling und Tracing - Die erste Stufe, Konfiguration: globale Prozessisolation, Code Coverage als Opt-in,
--order-by=defects, und für jeden weiteren Schalter die Frage, ob er ein Symptom behandelt oder eine Ursache
Ergebnis: Eine Baseline der Übungssuite, ihre langsamsten Tests als Ranking und eine bereinigte Konfiguration, neu gemessen
-
Sitzung 2: Testdesign (Kosten pro Test)
Welche Tests sind teurer, als sie sein müssten?
- Verkappte Integrationstests, die eine Datenbank treffen und sich Unit Tests nennen
- Fixtures, die vor jedem Test die Welt neu aufbauen, und unbemerkte Zugriffe auf Dateisystem und Netzwerk
- Überladene Mock-Setups und Framework-Bootstrap für pure Funktionen
- Gegenmittel: Lazy Fixtures, In-Memory-Datenbanken, Data Provider
- Testgrößen als Vertrag:
#[Small],#[Medium]und#[Large], Zeitlimits mitenforceTimeLimit, und kleine Tests ohne Netz, Datenbank, Dateisystem und Uhr
Ergebnis: Die teuersten Tests aus der ersten Sitzung, so umgebaut, dass sie weniger kosten, ohne weniger zu prüfen, und die fortgeschriebene Messreihe
-
Sitzung 3: Nicht jeder Test, nicht nur einmal (Anzahl ausgeführter Tests)
Welche Tests müssen jetzt laufen, und welche wie oft?
- Test-Index-Cache: Testdateien gar nicht erst laden
- Test Impact Analysis: welche Tests eine Änderung überhaupt betreffen kann, und was die Analyse bewusst nicht verspricht
-
--repeatund#[Repeat]: einen Test laufen lassen, bis er fehlschlägt, zur Diagnose von Tests, die unzuverlässig sind oder von der Reihenfolge abhängen -
--retryund#[Retry]: einen Test laufen lassen, bis er besteht, wobei jeder tolerierte Fehlschlag berichtet wird; ein Werkzeug für die Zeit zwischen Befund und Ursache - Ursachen unzuverlässiger Tests: geteilter Zustand, Zeit und Zufall, Nebenläufigkeit, fremde Systeme, Zeitzonen
- Kadenz: Testsuites und Gruppen für Commit, Merge, Nightly und Release, in der Konfigurationsdatei und über Optionen auf der Kommandozeile
Ergebnis: Die versteckten unzuverlässigen Tests der Übungssuite, gefunden mit
--repeat, eine begründete Retry-Policy und eine Kadenz, die festlegt, welche Tests wann laufen -
Sitzung 4: Nicht nacheinander (Parallelität)
Was muss stimmen, bevor Parallelisierung hilft?
- Warum Parallelisierung an vierter Stelle steht: Sonst läuft die Langsamkeit parallel, und geteilter Zustand macht Tests unzuverlässig
-
--parallelund seine Garantie byte-identischer Ausgabe, abgegrenzt gegen ParaTest - Datenbankisolation: Transaktions-Rollback, Template-Datenbanken in PostgreSQL, ein Container pro Worker
- Infrastruktur: RAM-Disk, Caching für Docker und Composer, Aufteilung in schnelle und langsame Gruppen, Sharding in der CI
- Warum erst die Event-Architektur seit PHPUnit 10 Index-Cache, Test Impact Analysis, Repeat, Retry und
--parallelmöglich gemacht hat
Ergebnis: Die parallelisierte Übungssuite ohne den Fehler, den geteilter Zustand erst dabei zeigt, die abgeschlossene Messreihe und ein Maßnahmenplan für deine eigene Suite
-
Sitzung 5: Die Ausgabe für Coding Agents
Was kostet ein Testlauf im Kontextfenster, und woran erkennt der Agent das Ergebnis?
- Das Kontextfenster als Arbeitsspeicher: was die Standardausgabe dort kostet
-
--compactundPHPUNIT_COMPACT_OUTPUT: Errors und Failures sofort, alles andere nach der Zusammenfassung - Die
--display-*-Optionen als gezielte Fragen, nicht als Reflex wie--display-all-issues - Warum
| tailund| grepInhalt und Exit-Code verlieren - Warum
OKin der Zusammenfassung kein Urteil ist:failOn*und der Exit-Code
Ergebnis: Ein Testlauf, dessen Ausgabe mit den Problemen wächst statt mit den Tests, der Kontextverbrauch eines Agenten mit und ohne kompakte Ausgabe im Vergleich, und der Exit-Code als Urteil
-
Sitzung 6: Coverage gezielt abfragen und verankern
Wie benennt ein Agent die Lücke, statt eine Zahl zu optimieren?
- Coverage als Opt-in: welche Aufgaben sie brauchen und welche nicht;
--coverswählt die verantwortlichen Tests ohne Coverage-Treiber aus -
--coverage-jsonlmitmeta.json,coverage.jsonlundtests.jsonl, abgefragt mitgrepundjq - Eingeschränkte Läufe mit
--filterund was „uncovered“ dann bedeutet,Covers*-Attribute und Branch Coverage, die trotz vollständig ausgeführter Zeilenpartialmeldet - Eine nicht ausgeführte Zeile als Frage statt als Ziel
- Was nur im Prompt steht, vergisst der Agent. Drei Mechanismen halten es fest: Anweisung (
AGENTS.md,CLAUDE.md, Junie-Guidelines), Umgebung (Umgebungsvariablen, Composer-Skripte, freigegebene Kommandos) und Leitplanke (Hooks, die gefilterte Testläufe abweisen) - Den Bericht des Agenten prüfen, statt ihm zu glauben
Ergebnis: Abfragen der Coverage im JSONL-Format, die die Lücke statt eines Prozentwerts liefern, und dein eigenes Projekt, eingerichtet mit Anweisung, Umgebung und Leitplanke
- Coverage als Opt-in: welche Aufgaben sie brauchen und welche nicht;
Für wen
- Entwicklerinnen und Entwickler, deren Testsuite so langsam ist, dass sie seltener läuft, als sie sollte
- Teams mit unzuverlässigen Tests, die mal grün und mal rot sind
- Tech Leads, die die Testausführung in der CI verantworten
- Entwicklerinnen und Entwickler, die Coding Agents wie Claude Code oder Junie Tests ausführen lassen
Voraussetzungen
- Sichere Praxis mit PHPUnit, etwa nach „Agentic PHPUnit“; Testisolation und Test Doubles als Begriffe vermittelt „Testen verstehen“
- Idealerweise eine eigene Testsuite, die dir zu langsam ist
- Für die Sitzungen 5 und 6 eigene Erfahrung mit einem Coding Agent; Kosten und Kontingent für deinen Agenten trägst du selbst
- Für die Übungen PHP 8.4 oder neuer, Composer und Git, oder Podman bzw. Docker für den bereitgestellten Container
- Für die Arbeit an deinem eigenen Projekt am besten PHPUnit 14, mindestens 13.4
Das nimmst du mit
- Du erhebst eine Baseline deiner Suite und weißt, welche Tests die Zeit verbrauchen
- Du ordnest jede Maßnahme einem Term der Feedbackformel zu und wählst die richtige Reihenfolge
- Du findest unzuverlässige Tests mit
--repeatund begründest, wann#[Retry]vertretbar ist - Du parallelisierst eine Suite, ohne dass geteilter Zustand sie unzuverlässig macht
- Du richtest dein Projekt so ein, dass ein Coding Agent kompakt testet, das Ergebnis am Exit-Code abliest und Coverage-Lücken benennt, statt einen Prozentwert zu optimieren
- Du hast einen Maßnahmenplan für deine eigene Testsuite
Verwandte Schulungen
Diese Schulung ist Teil der Lernpfade Testen mit PHPUnit, Arbeiten mit KI-Agenten.
Dein Trainer
Sebastian Bergmann ist der Schöpfer von PHPUnit, dem De-facto-Standard für das Testen von PHP-Code. Seit 2001 hilft er Teams als Berater und Trainer dabei, wartbare und gut getestete Software zu bauen, seit 2009 als Mitgründer von thePHP.cc.
Die Schulung baut auf seinem Vortrag „Turbo-Charging Your PHPUnit Suite“ auf, den er 2026 auf der International PHP Conference gehalten hat. Was er dort zeigt, steht auch in seinem gleichnamigen Artikel.