Die Welt der PHP-Testautomatisierung hat sich mit der Veröffentlichung von PHPUnit 12.5 wieder einen Schritt weiterentwickelt. In unserer neuesten Never-Code-Alone Session hatten wir das Privileg, mit Sebastian Bergmann, dem Schöpfer von PHPUnit, über die Neuerungen zu sprechen – und die Details sind so praktisch wie inspirierend.
Die zwei großen Highlights in PHPUnit 12.5
1. Die erleuchtende Unterscheidung: Stubs vs. Mocks
Seit Jahren verwenden Entwickler die Begriffe „Stubs“ und „Mocks“ synonym, doch PHPUnit 12.5 bringt endlich Klarheit in diese babylonische Sprachverwirrung:
Test Stubs verwenden wir, um uns von Abhängigkeiten zu entkoppeln, die indirekte Eingabe liefern. Beispiel: Ein Database-Repository, das fest definierte Daten zurückgibt, ohne mit einer echten Datenbank zu sprechen.
Mock Objects benötigen wir dagegen, wenn wir indirekte Ausgabe testen wollen – also die Kommunikation zwischen Objekten. Beispiel: Sicherstellen, dass ein Service nach einer Aktion tatsächlich einen Logger aufruft.
// Bisher: Immer createMock() verwendet
$databaseMock = $this->createMock(Database::class);
// Jetzt in PHPUnit 12.5: Besserer Ansatz
$databaseStub = $this->createStub(Database::class);
$databaseStub->method('query')->willReturn(['data']);
// ODER bei tatsächlich benötigtem Mock:
$loggerMock = $this->createMock(Logger::class);
$loggerMock->expects($this->once())
->method('log')
->with('error', 'Something went wrong');
Die neue PHPUnit Notice warnt dich nun, wenn du createMock() ohne konfigurierte Erwartungen verwendest – ein sanfter Hinweis, dass du wahrscheinlich nur einen Stub brauchst.
2. Performance-Explosion für Infection
Markus Staab hat signifikante Verbesserungen am Code-Coverage-XML-Format von PHPUnit vorgenommen, was zu einem 40-50% Performance-Boost für Infection (das Mutation-Testing-Tool) führte. Der Trick: Das optionale Weglassen des <source>-Elements im Coverage-Report, das für statische Code-Analyse vorverarbeitete Tokens enthielt – eine Information, die Infection gar nicht benötigt.
Praktische Implikationen für deine Test-Suite
Bessere Test-Lesbarkeit durch klare Intention
Wenn du in deinen Tests konsequent createStub() für Eingabe-Abhängigkeiten und createMock() nur für Ausgabe-Überprüfungen verwendest, wird dein Testcode selbsterklärender. Neue Teammitglieder (oder dein zukünftiges Ich) können schneller erfassen, was ein Test eigentlich prüfen soll.
// Klare Intention: Nur Eingabe steuern
$userRepositoryStub = $this->createStub(UserRepository::class);
$userRepositoryStub->method('findAll')->willReturn([$user1, $user2]);
// Klare Intention: Ausgabe überprüfen
$emailServiceMock = $this->createMock(EmailService::class);
$emailServiceMock->expects($this->exactly(2))
->method('send');
Die neue Notice-Stufe: Dein freundlicher Code-Reviewer
PHPUnit führt eine neue Notice-Stufe ein, die zwischen „risky“ und kompletter Ignoranz liegt. Die erste Notice dieser Art warnt vor unkonfigurierten Mock-Objects. Du kannst sie pro Klasse mit einem Attribut deaktivieren:
#[AllowMockingUnknownTypes]
class MyCustomTestCase extends TestCase
{
// Dein Test-Code
}
Dieser Ansatz verhindert, dass Teams die Notice global abschalten und so das wertvolle Feedback verlieren.
Wie du dich auf PHPUnit 13 vorbereitest
PHPUnit folgt einem vorhersagbaren Release-Zyklus:
- Februar jedes Jahres: Major-Release (z.B. PHPUnit 13) mit Breaking Changes
- Dezember: Feature-Release (z.B. 12.5) als letzte Version einer Serie
Für den Übergang zu PHPUnit 13 solltest du:
- Die Deprecation-Warnungen in 12.5 ernst nehmen – sie zeigen dir, was sich in 13.0 ändern wird
Auf typsichere Assertions umsteigen:
// Deprecated in 12.5, entfernt in 13.0:
$this->assertIsType('array', $value);
// Neu und typsicher:
$this->assertIsArray($value);
$this->assertIsBool($value);
$this->assertIsCallable($value);- Tools wie Rector nutzen, um die Migration zu automatisieren
Wie du zu PHPUnit beitragen kannst (auch ohne tiefes Framework-Wissen)
Sebastian betonte im Gespräch mehrere Wege, wie Entwickler zum Projekt beitragen können:
- Feedback geben: „Das Feature verstehe ich nicht“ oder „Hier hakt es“ ist extrem wertvoll
- Bug-Reports reproduzieren: Selbst wenn du den Fix nicht kennst, hilft Bestätigung
- Dokumentation verbessern: Unklare Stellen aufzeigen oder direkt verbessern
- Good-First-Isses im Issue-Tracker ansehen
Ein konkreter Einstiegspunkt: Neue Assertions schreiben. Die Struktur in PHPUnit ist konsistent:
- Jede Assertion hat eine inverse Variante (
assertHasKey/assertNotHasKey) - Die Logik wird in
Constraint-Objekten gekapselt - Tests verwenden Data Provider für verschiedene Eingabeszenarien
Die menschliche Seite von Open-Source-Maintenance
Sebastian gab einen ehrlichen Einblick in die Herausforderungen von Open-Source-Maintenance:
- Jeder akzeptierte Pull Request bedeutet langfristige Verantwortung
- Feature-Requests direkt mit PRs zu verbinden ist riskant (viel investierte Zeit vs. mögliche Ablehnung)
- Das größte Geschenk für Maintainer ist konstruktives Feedback
Schulungsangebote und Ressourcen
Für Entwickler, die tiefer einsteigen wollen:
- Testautomation mit PHPUnit: Einstiegskurs für verlässlichen Code (Januar, 4×2 Stunden)
- What’s new in PHP 8.5: Update-Schulung zu den neuesten PHP-Features
- Debugging deep dive: Techniken jenseits von XDebug
Alle Artikel und Ressourcen zum Thema findet ihr auf phpunit.expert – inklusive eines ausführlichen Artikels zu Stubs und Mocks, der die heutige Diskussion vertieft.
Fazit: PHPUnit wird erwachsener – und hilfreicher
PHPUnit 12.5 markiert einen wichtigen Schritt in der Evolution des Frameworks. Es geht nicht mehr nur um reine Funktionalität, sondern um Developer Experience und Code-Qualität durch bessere Feedback-Loops. Die neue Unterscheidung zwischen Stubs und Mocks, kombiniert mit den hilfreichen Notices, macht PHPUnit zu einem noch besseren Lehrer für Test-Driven Development.
Die größte Erkenntnis aus dem Gespräch: 90% der Fälle, in denen du Test Doubles brauchst, sind Stubs – keine Mocks. Wenn du also das nächste Mal createMock() schreibst, frage dich: „Teste ich hier wirklich die Kommunikation zwischen Objekten, oder will ich nur Eingabe steuern?“
Timestamps aus dem Video:
- 00:00 Begrüßung & Einführung PHPUnit 12.5 mit Sebastian Bergmann
- 06:45 Die philosophische Frage: Wer contributet zu PHPUnit?
- 22:10 Kernkonzept erklärt: Test Stubs vs. Mock Objects – der fundamentale Unterschied
- 41:30 Live-Demo: Neue PHPUnit Notice für unkonfigurierte Mock Objects
- 58:15 Performance-Story: Wie Markus Staab Infection um 40-50% beschleunigte
- 1:15:45 Contributing Guide: Vom Issue bis zum ersten Pull Request
- 1:29:20 Code-Deep Dive: Wie eine PHPUnit Assertion intern funktioniert
- 1:41:10 Ausblick PHPUnit 13, Deprecations & Schulungsangebote
- 1:49:00 Verabschiedung
Habt ihr bereits Erfahrung mit den neuen Features von PHPUnit 12.5 gemacht? Teilt eure Gedanken in den Kommentaren!
