Antworten auf Fragen, die mir immer wieder zu PHPUnit, Testautomatisierung, Code Coverage und dem Testen in PHP gestellt werden. Wo es passt, verweist eine Antwort auf einen ausführlichen Artikel.
Nutze PCOV, wenn dir Line Coverage genügt: Es ist deutlich schneller und ideal für die CI. Greife zu Xdebug, wenn du Branch- oder Path Coverage brauchst oder Xdebug ohnehin schon zum Debuggen einsetzt. Beide gleichzeitig zu aktivieren, ergibt selten Sinn.
Mehr dazu im Artikel: PCOV oder Xdebug?
Ja. Sammle die Coverage für jeden Lauf getrennt, etwa wenn du deine Suite shardest oder parallelisierst, exportiere sie im PHP- oder Cobertura-Format und führe die Berichte anschließend zusammen. So erhältst du einen Gesamtwert, ohne alle Tests in einen einzigen Lauf zwingen zu müssen.
Mehr dazu im Artikel: Code Coverage-Daten zusammenführen
Line Coverage sagt nur, welcher Code ausgeführt wurde, nicht, ob deine Assertions wirklich etwas prüfen. Path Coverage zeigt ungetestete Kombinationen von Verzweigungen, und Mutation Testing misst, ob deine Tests eine Änderung am Code überhaupt bemerken würden. Beides deckt Vertrauen auf, das Coverage allein nicht belegt.
Mehr dazu im Artikel: Path Coverage oder Mutation Testing?
withConsecutive() wurde in PHPUnit 10 entfernt. Ersetze es durch einen einzelnen willReturnCallback(), der die Argumente prüft, bei Bedarf kombiniert mit dem Invocation-Matcher aus $this->exactly(), sodass du auf jeden Aufruf anhand seiner Nummer reagieren kannst. Das ist ausführlicher, aber deutlich klarer in dem, was jeder Aufruf erwartet.
Mehr dazu im Artikel: Besser als withConsecutive()
Nutze einen Stub, wenn ein Kollaborateur nur vorgegebene Werte liefern soll, damit der getestete Code läuft. Nutze einen Mock, wenn gerade die Interaktion selbst überprüft werden soll. Aufrufe zu verifizieren, die keine Rolle spielen, koppelt deine Tests an die Implementierung und macht sie brüchig.
Mehr dazu im Artikel: Die Stub-/Mock-Intervention
Es gibt vier Ebenen, die du dir ansehen solltest: die Konfiguration des Test-Runners, die Infrastruktur, die deine Tests berühren, die Parallelisierung und das Design der Tests selbst. Die größten und nachhaltigsten Gewinne kommen fast immer aus besserem Test-Design, nicht daraus, einer langsamen Suite mehr Kerne zu geben.
Mehr dazu im Artikel: Turbo-Charging Your PHPUnit Suite
Miss, bevor du irgendetwas änderst. Ein Profiler zeigt dir, wohin Zeit und Speicher tatsächlich fließen, und das ist regelmäßig woanders als vermutet. Raten und nach Bauchgefühl zu optimieren, macht den Code meist komplexer, ohne ihn schneller zu machen.
Mehr dazu im Artikel: Debugging von Performance in PHP
Testbarer Code hält seine Abhängigkeiten explizit und austauschbar, trennt Entscheidungen von Seiteneffekten und verzichtet auf den Griff in globalen Zustand. Wenn eine Klasse anfordert, was sie braucht, statt es sich selbst zu holen, lässt sie sich ohne aufwendiges Setup unter Test stellen.
Mehr dazu im Artikel: Was macht Code eigentlich testbar?
Bilde die Struktur des getesteten Codes ab, gib jedem Test einen klaren Grund zu scheitern und mache die Phasen Arrange, Act und Assert gut erkennbar. Ein Test, den du in wenigen Sekunden liest, ist einer, dem du vertraust und den du pflegst.
Mehr dazu im Artikel: Best Practices für die Teststruktur
Trenne die Logik, die Abfragen aufbaut und auswertet, von dem Code, der sie ausführt, damit die meisten deiner Tests gar keine Datenbank brauchen. Für den Teil, der wirklich von der Datenbank abhängt, teste gegen eine echte Instanz statt gegen einen Mock, denn dort verstecken sich die Überraschungen.
Mehr dazu im Artikel: Testbare Datenbankinteraktion
Kapsle ein Array in einer eigenen Klasse, die nur den gewünschten Typ annimmt, biete genau die Operationen an, die du wirklich brauchst, und lass die statische Analyse den Elementtyp über Generics-Annotationen prüfen. Du gewinnst Sicherheit und eine klare API, statt rohe Arrays herumzureichen.
Mehr dazu im Artikel: Typsichere Collections
Statt einzelne Beispiele zu prüfen, formulierst du eine Eigenschaft, die für alle gültigen Eingaben gelten soll, und lässt ein Werkzeug viele davon erzeugen, auch Randfälle, an die du nicht denken würdest. Findet es einen Fehler, verkleinert es die Eingabe auf den kleinsten Fall, der noch scheitert.
Mehr dazu im Artikel: Property-Based Testing
Für fast jede Schwachstelle, die es in Produktion schafft, gibt es einen Test, der sie verhindert hätte, hätte es ihn gegeben. Test-Driven Security behandelt bekannte Schwachstellenkategorien als Checkliste und nutzt die Testwerkzeuge, die du ohnehin hast, um die Abwesenheit jeder Fehlerklasse zu belegen.
Mehr dazu im Artikel: Test-Driven Security
Ja. Ist deine Suite zu langsam, um sie oft laufen zu lassen, können auch automatische Werkzeuge und KI-Agenten sie nicht zur Prüfung ihrer Änderungen nutzen, und Schwachstellen bleiben länger verborgen. Was früher rein als Produktivitätsproblem galt, gehört heute zur Sicherheitsdebatte.
Mehr dazu im Artikel: Geschwindigkeit als Sicherheitsmerkmal
Nein. PHPUnit ist eine Entwicklungsabhängigkeit: Fordere es unter require-dev an und stelle sicher, dass es niemals in deinem Produktiv-Deployment oder Autoloader landet. Testwerkzeuge in Produktion auszuliefern, vergrößert die Angriffsfläche ohne Not.
Mehr dazu im Artikel: PHPUnit: Ein Sicherheitsrisiko?
Ja. Ich biete maßgeschneiderte Workshops und Schulungen zu PHPUnit, Testautomatisierung und testbarem Software-Design, remote oder vor Ort. Die aktuellen Themen findest du im Schulungsbereich.
Das ist ein großer Teil meiner Arbeit. Durch Beratung und Coaching helfe ich Teams, Legacy-Code unter Test zu bringen und die Gewohnheiten aufzubauen, die ihn dort halten. Der Beratungsbereich beschreibt, wie das abläuft.