Ursprünglich habe ich diesen Artikel am 5. Juni 2026 als Newsletter an meine Abonnentinnen und Abonnenten verschickt. Weitere Informationen findest du am Ende dieses Artikels.
PHPUnit 13.2 ist ein Release über Präzision und Klarheit. Es gibt dir mehr Kontrolle darüber, welche Tests in welcher Reihenfolge laufen. Es macht die Rückmeldungen bei fehlschlagenden Tests schneller und besser lesbar. Und es bietet ausdrucksstärkere Möglichkeiten, das Verhalten deiner Test Doubles zu beschreiben.
Genau die Tests ausführen, die du willst
PHPUnit erlaubt es schon immer, einen Testlauf auf eine Teilmenge der Testsuite einzugrenzen, zum Beispiel nach Testsuite, nach Gruppe oder mit der Option --filter und ihren regulären Ausdrücken. Reguläre Ausdrücke sind mächtig, aber auch fehleranfällig. Ein Muster kann mehr Tests erfassen als beabsichtigt oder wegen eines einzigen nicht maskierten Zeichens gar nicht greifen.
PHPUnit 13.2 ergänzt einen präziseren Mechanismus rund um Test-IDs. Eine Test-ID ist ein stabiler Bezeichner, der einen einzelnen Test eindeutig benennt, einschließlich des konkreten Datensatzes bei Tests, die von einem Data Provider gespeist werden. Die neue Option --list-test-ids (#6575) gibt jeden Test der Suite als Test-ID aus. Die Option --run-test-id (#6577) führt genau den einen Test aus, auf den die übergebene ID verweist, und zwar über exakte Übereinstimmung statt über ein Muster.
Darauf aufbauend kannst du PHPUnit jetzt eine ganze Liste auszuführender Tests übergeben (#3387). Die Option --test-id-filter-file liest eine Datei mit einer Test-ID pro Zeile und führt genau diese Tests aus. Das ist besonders nützlich für Werkzeuge und Continuous Integration. Ein vorheriger Lauf kann die IDs der fehlgeschlagenen Tests festhalten, sodass ein späterer Lauf nur diese erneut ausführt. Oder ein Build verteilt eine große Suite, indem er jedem Worker seine eigene Liste von IDs übergibt. Auch die Option --filter versteht jetzt die Test-ID-Syntax (#6575). So kannst du die vertraute Option weiterverwenden und gewinnst zugleich die Präzision von Test-IDs.
Eine verwandte Änderung macht das Filtern schneller und zugleich korrekter (#6609). Wenn der Test, den ein Data Provider speist, unmöglich auf das aktive --filter-Muster passen kann, überspringt PHPUnit die Ausführung dieses Data Providers jetzt vollständig, anstatt ihn auszuführen und sein Ergebnis anschließend zu verwerfen.
Die Reihenfolge der Tests
Wenn du entschieden hast, welche Tests laufen sollen, gibt dir PHPUnit 13.2 mehr Kontrolle über die Reihenfolge, in der sie laufen. Der Test Runner kann Tests bereits nach Größe, nach Dauer oder nach ihren deklarierten Abhängigkeiten sortieren, zuvor fehlgeschlagene Tests zuerst ausführen oder eine zufällige Reihenfolge wählen.
Die Sortierung nach Dauer erhält eine absteigende Variante (#6075). So kannst du die langsamsten Tests zuerst ausführen statt zuletzt. Da nun beide Richtungen existieren, sind die alten richtungsneutralen Werte mehrdeutig geworden. Die Optionen --order-by duration und --order-by size sowie die entsprechenden Werte executionOrder="duration" und executionOrder="size" in der XML-Konfigurationsdatei sind deshalb zugunsten der eindeutigen Varianten duration-ascending, duration-descending, size-ascending und size-descending deprecated.
Auch die Sortierung „defekte Tests zuerst“ wurde verfeinert. Bisher wurden nicht nur Tests bevorzugt, die Errors oder Failures erzeugten, sondern auch solche, die Deprecations, Notices oder Warnings auslösten, sowie unvollständige, riskante und übersprungene Tests. Ab PHPUnit 13.2 gelten für die Sortierung nur noch Errors und Failures als Defekte. Damit entspricht das Verhalten dem, was die meisten erwarten: Die Tests, die tatsächlich kaputtgegangen sind, laufen zuerst.
Schließlich akzeptiert das Attribut executionOrder in der XML-Konfigurationsdatei jetzt reichhaltigere Kombinationen. Du kannst defects mit jeder Hauptsortierung kombinieren und sogar Dreierkombinationen aus Abhängigkeitsauflösung, Defekt-Priorisierung und einer Hauptsortierung ausdrücken, etwa depends,defects,duration-ascending. Außerdem wurde ein Sortierfehler behoben, der Testsuites aus TestCase-Klassen falsch behandelte (#6582).
Schnellere, klarere Fehlermeldungen
Wenn ein Test fehlschlägt, zählen zwei Dinge: wie schnell PHPUnit dir sagen kann, was schiefgelaufen ist, und wie leicht sich diese Erklärung lesen lässt. PHPUnit 13.2 verbessert beides.
Die größte Geschwindigkeitsverbesserung stammt aus einem Dependency-Update. PHPUnit 13.2 wird mit Version 9 von sebastian/diff ausgeliefert, der Bibliothek, die die Diffs erzeugt, die du bei einem fehlgeschlagenen Vergleich siehst. Ihr Diff-Algorithmus wurde durch eine Implementierung von Eugene W. Myers' Algorithmus mit linearem Speicherbedarf ersetzt (Pull Request #138). Bei großen, weitgehend identischen Eingaben ist der Unterschied dramatisch. In einem Benchmark, der zwei Dateien mit rund 18.000 Zeilen vergleicht, die sich in etwa 200 Zeilen unterscheiden, sank die Erzeugung des Diffs von mehreren Sekunden auf wenige Millisekunden. Wenn du jemals zugesehen hast, wie PHPUnit beim Erzeugen des Diffs für eine fehlgeschlagene Assertion auf einem großen String oder Array zu hängen schien, dann ist das die Änderung, die das behebt.
Du kannst jetzt auch steuern, wie viel Kontext ein Diff anzeigt. Die neue Option --diff-context (#6567) legt die Anzahl der unveränderten Zeilen fest, die rund um jede Änderung angezeigt werden; der Standardwert ist drei. Erhöhe sie, wenn du mehr vom Umfeld sehen möchtest, oder verringere sie, um die Ausgabe knapp zu halten.
Manche Fehlermeldungen sind weniger überladen. Die Constraints IsTrue, IsFalse, IsNull, IsFinite, IsInfinite und IsNan geben das übergebene Array oder Objekt nicht mehr vollständig aus (#5810). Bei einer Prüfung, die nur fragt, ob ein Wert etwa true oder null ist, sorgte die vollständige Ausgabe des Werts für Unübersichtlichkeit, ohne Information hinzuzufügen.
Für Läufe mit viel Ausgabe wechselt die neue Option --compact zu einer kompakteren Konsolenausgabe (#6597). Sie lässt sich auch über die Umgebungsvariable PHPUNIT_COMPACT_OUTPUT=1 aktivieren.
PHPUnit 13.2 ergänzt außerdem Assertions, die Strings vergleichen und dabei Unterschiede im Whitespace ignorieren (#5757), einschließlich Varianten, die den erwarteten oder tatsächlichen Wert aus einer Datei lesen. Diese sind praktisch beim Vergleich generierter Ausgaben wie Quellcode oder HTML, bei denen Einrückung und Zeilenumbrüche für die Korrektheit irrelevant sind.
Ein verlässlicherer Test Runner
Ein Test Runner muss sich die PHP-Laufzeitumgebung mit dem Code teilen, den er testet. Mehrere Änderungen in PHPUnit 13.2 machen ihn zu einem rücksichtsvolleren Gast.
Die bedeutendste davon betrifft Error Handler. Wenn deine Anwendung vor dem Start von PHPUnit einen Error Handler registriert hatte, etwa über eine auto_prepend_file-Direktive oder ein Bootstrap-Skript, ersetzte PHPUnit ihn bisher stillschweigend. Das deaktivierte nicht nur Verhalten, auf das du dich möglicherweise verlassen hast, es konnte auch falsche Warnungen über „riskante Tests“ erzeugen (#5845). PHPUnit 13.2 reiht den zuvor registrierten Handler jetzt in eine Kette ein, anstatt ihn zu deaktivieren (#5873). So können sowohl PHPUnit als auch deine eigene Fehlerbehandlung ihre Aufgabe erfüllen.
Tests, die PHPs Output Buffering manipulieren, konnten bisher die Ausgabeerfassung von PHPUnit durcheinanderbringen. Die Folge waren falsch erfasste Ausgaben, Hänger und sogar stille Fehlschläge. Das wurde behoben (#5851). Issues wie Deprecations, Notices und Warnings, die außerhalb des Geltungsbereichs eines Tests ausgelöst werden, etwa während des Bootstrappings, werden jetzt korrekt behandelt, anstatt falsch zugeordnet zu werden oder verloren zu gehen (#6579).
Auch das Abbrechen eines Laufs ist freundlicher geworden. Wenn du einen Lauf abbrichst, etwa mit Strg-C, behandelt PHPUnit den Abbruch jetzt sauber und zeigt dir die bis dahin gesammelten Ergebnisse, anstatt einfach zu beenden (#4201).
Zwei weitere Änderungen helfen dir, Fehler beim Aufruf von PHPUnit zu erkennen. Die neue Option --validate-configuration prüft deine XML-Konfigurationsdatei auf Probleme. Und PHPUnit gibt jetzt eine Warnung aus, wenn du widersprüchliche Kommandozeilenoptionen übergibst, anstatt stillschweigend die eine zu berücksichtigen und die andere zu ignorieren (#6346).
Ausdrucksstärkere Test Doubles
PHPUnit 13.2 vervollständigt die Familie von Erwartungen, die die entfernte Methode withConsecutive() ersetzt hat. In einem früheren Artikel habe ich withParameterSetsInOrder() beschrieben, das Parameter-Sets in einer exakten Reihenfolge erwartet, sowie withParameterSetsInAnyOrder(), das sie in beliebiger Reihenfolge erwartet. Reale Interaktionen liegen oft zwischen diesen beiden Extremen. Die neue Regel withParameterSetsInPartialOrder() (#6606) deckt diesen Mittelweg ab: Du kannst einige Parameter-Sets an feste Positionen binden und die übrigen ungeordnet lassen.
Auch das Stubben von Rückgabewerten ist präziser geworden (#6574). Die Methode willReturnMap(), die Sätze von Argumenten den dafür zurückzugebenden Werten zuordnet, akzeptiert jetzt neben literalen Werten auch Constraints. So kann eine Zuordnung Argumente über eine Regel abgleichen statt nur über den exakten Wert. Eine neue Methode willReturnStrictMap() nutzt einen strikten Vergleich beim Abgleich der Argumente und vermeidet so die Überraschungen, die ein loser Vergleich verursachen kann.
Schließlich lassen sich Erwartungen an Exception-Nachrichten klarer ausdrücken. Die altbekannte Methode expectExceptionMessage() war irreführend benannt: Trotz ihres Namens verlangte sie nie, dass die Nachricht gleich der erwarteten Zeichenkette ist, sondern nur, dass sie diese enthält. PHPUnit 13.2 führt eine explizite API ein (#6559):
-
expectExceptionMessageIs()verlangt eine exakte Übereinstimmung -
expectExceptionMessageIsOrContains()behält das vertraute Teilstring-Verhalten bei -
expectExceptionMessageMatches()bleibt für reguläre Ausdrücke verfügbar
Tests, die expectExceptionMessage() verwenden, das jetzt deprecated ist, sollten auf eine der obigen Methoden migriert werden.
Livestream
Hier ist die Aufzeichnung des Livestreams, in dem ich die wichtigsten Änderungen in PHPUnit 13.2 erläutert habe:
Exklusive Einblicke direkt in deinem Posteingang
Alle zwei Monate, zeitgleich mit jedem PHPUnit Feature Release, schicke ich meinen Abonnentinnen und Abonnenten eine ausführliche Einordnung der neuen Funktionen: was sie tun, wie sie implementiert sind und warum sie aufgenommen wurden. Das ist der Kontext, den das ChangeLog nicht liefert.
Den Inhalt des Newsletters veröffentliche ich einen Monat nach dem Versand an meine Abonnenten hier auf dieser Website. Jetzt abonnieren, um die Informationen so früh wie möglich zu erhalten.