NCA Social Media
Erstellt:
Aktualisiert:
Autor:
Roland Golla
Infrection Framework Logo

Infection Framework: Mutation Testing für PHP 2026

Das Infection Framework ist das Mutation Testing Tool für PHP. Es verändert deinen Quellcode an vielen kleinen Stellen und prüft, ob deine Tests diese Änderungen bemerken. Jede Änderung heißt Mutant. Bleibt die Test Suite grün, hat der Mutant überlebt und du kennst eine echte Lücke in deinen Assertions.
Code Coverage sagt dir nur, welche Zeilen ausgeführt wurden. Mutation Testing sagt dir, ob deine Tests bei einem Fehler auch wirklich rot werden. Genau diesen Unterschied macht Infection sichtbar.
Code:
          

composer require --dev infection/infection

Infection arbeitet auf dem Abstract Syntax Tree deines Codes. Es unterstützt PHPUnit, PhpSpec, Codeception und Testo, braucht PHP 8.3 oder neuer und einen Coverage Treiber wie Xdebug, phpdbg oder pcov. Die zentrale Kennzahl ist der Mutation Score Indicator, kurz MSI.

Mutation Testing mit NCA: Schnelle Hilfe vom Experten

Testing ist unser Kerngeschäft. Wir arbeiten täglich mit PHPUnit, PHPStan, Psalm und Rector in Symfony Projekten. Roland Golla entwickelt seit über 20 Jahren PHP und ist Cypress Ambassador. Mutation Testing setzen wir dort ein, wo eine Test Suite auf dem Papier gut aussieht und im Ernstfall trotzdem nichts meldet. Unsere Reihenfolge ist immer gleich: erst Quality Gates, dann Aufräumen.
Wir bringen Infection in bestehende Projekte, ohne dass die Pipeline stehen bleibt. Dazu passen unsere Leistungen rund um PHP Refactoring, Legacy Modernisierung, PHP Update und die CI CD Pipeline mit Docker und Staging. Wer KI Werkzeuge im Team nutzt, bekommt mit den NCA PHP AI Coding Guidelines den passenden Rahmen. Einen Überblick über alle Themen gibt das PHP Consulting von Never Code Alone.
Mutation Testing im PHP Projekt einführen
Finde das passende Angebot für dein Projekt
Anfrage-Konfiguration
Starten Sie Ihre Anfrage
Projektart
Infos
Nachricht

Eliminierung technischer Schulden mit PHPStan, Rector PHP und PHPUnit. Über 20 Jahre Praxiserfahrung in skalierbaren Backends.

CORE EXPERTISE

Gesetzliche Konformität & Inklusion. Optimierung von Performance und Conversion durch radikal nutzerzentriertes, universelles Design.

BFSG COMPLIANT

Skalierbare KI-Systeme mit echtem Code Ownership. CI/CD, Backup-Strategien und Infrastruktur, die mit deinem Team wächst.

ENTERPRISE READY

Installation und Voraussetzungen

Infection braucht PHP 8.3 oder neuer und einen Coverage Treiber. Ohne Coverage Daten weiß das Tool nicht, welche Tests eine mutierte Zeile abdecken. Ältere PHP Versionen laufen nur mit älteren Infection Versionen, die Versionstabelle steht in der offiziellen Dokumentation.
Der übliche Weg im Projekt ist Composer als Dev Abhängigkeit.
Code:
          

composer require --dev infection/infection

Das offizielle Team empfiehlt für den lokalen Rechner die PHAR Variante. Sie bringt die Adapter für PHPUnit, PhpSpec, Codeception und Testo direkt mit und hält deine composer.json schlank. Die PHAR ist mit einem GPG Key signiert, du kannst die Signatur vor dem ersten Start prüfen.
Code:
          

chmod +x infection.phar
./infection.phar --version

Als Coverage Treiber ist pcov die schnellste Wahl. Xdebug brauchst du nur, wenn du Branch oder Path Coverage auswertest. Wie du Coverage sauber misst, steht im Glossareintrag zu phpcov.

Konfiguration mit infection.json5

Die Konfiguration liegt im Wurzelverzeichnis deines Projekts. Infection legt sie beim ersten Start selbst an und fragt dich nach den Quellverzeichnissen. Das Format ist JSON5, Kommentare sind also erlaubt.
Code:
          

{
    "source": {
        "directories": [
            "src"
        ]
    },
    "logs": {
        "text": "var/log/infection.log",
        "html": "var/log/infection.html"
    },
    "mutators": {
        "@default": true
    },
    "minMsi": 70,
    "minCoveredMsi": 80
}

Wichtig sind drei Stellschrauben. source.directories grenzt ein, welcher Code überhaupt mutiert wird. mutators steuert, welche Mutationsoperatoren laufen, von der Standardmenge bis zu einzelnen Profilen. minMsi legt fest, ab welchem Wert der Build rot wird.
Starte mit einer niedrigen Schwelle. Nimm den Wert, den dein Projekt heute erreicht, und zieh ihn Schritt für Schritt an. Ein zu hoher Startwert blockiert nur die Pipeline und das Team schaltet die Prüfung wieder ab.

Infection ausführen: die wichtigsten Optionen

Der einfachste Start ist ein Lauf ohne Argumente. Infection führt zuerst die komplette Test Suite aus, sammelt Coverage und mutiert danach. Seit Version 0.33.2 laufen die Mutanten dabei standardmäßig auf mehreren Prozessen statt auf einem einzigen.
Code:
          

vendor/bin/infection

Willst du nur einen Teil des Codes prüfen, hängst du Pfade direkt an den Befehl. Diese Positional Arguments kamen mit 0.34.0, die alte Option --filter gilt seitdem als veraltet.
Code:
          

vendor/bin/infection src/Service/Payment.php --min-msi=70 --show-mutations

Für den Alltag zählen vor allem diese Optionen:
  • --threads=4 setzt die Zahl der Prozesse fest, wenn dir die automatische Wahl nicht passt.
  • --min-msi=70 lässt den Befehl mit Fehlercode enden, wenn der MSI unter der Schwelle liegt.
  • --min-covered-msi=80 prüft nur den Code, der von Tests abgedeckt ist.
  • --show-mutations zeigt die überlebenden Mutanten als Diff direkt in der Konsole.
  • --git-diff-lines mutiert nur die Zeilen, die im aktuellen Branch geändert wurden.
  • --coverage=build nutzt bereits erzeugte Coverage Daten statt eines neuen Testlaufs.
  • --test-framework-extra-args reicht zusätzliche Argumente an PHPUnit durch.
Wer den Testlauf selbst beschleunigen will, kombiniert Infection mit Paratest. Die Coverage aus dem regulären PHPUnit Lauf lässt sich direkt weiterreichen.
Code:
          

vendor/bin/phpunit --coverage-xml=build/coverage-xml --log-junit=build/phpunit.junit.xml
vendor/bin/infection --coverage=build

MSI, Mutation Code Coverage und Covered Code MSI verstehen

Nach jedem Lauf zeigt Infection drei Kennzahlen. Sie sehen ähnlich aus und messen völlig Verschiedenes.
Code:
          

Metrics:
    Mutation Score Indicator (MSI): 47%
    Mutation Code Coverage: 67%
    Covered Code MSI: 70%

Der MSI ist die Hauptkennzahl. Er sagt, wie viel Prozent aller erzeugten Mutanten erkannt wurden. Dazu zählen getötete Mutanten, Timeouts und Fehler. In diesem Beispiel liegen 47 Prozent MSI gegen 67 Prozent Code Coverage. Die Lücke von 20 Punkten ist der Teil deiner Testsuite, der Zeilen ausführt, ohne sie zu prüfen.
Die Mutation Code Coverage liegt normalerweise in der Nähe deiner normalen Coverage. Der Covered Code MSI ignoriert ungetesteten Code und beantwortet die eigentlich spannende Frage: Wie gut sind die Tests, die es schon gibt? Für die tägliche Arbeit ist dieser Wert oft der ehrlichste. Wie du das gleiche Prinzip auf geänderte Zeilen anwendest, steht bei Patch Coverage.

Infection Kennzahlen im Überblick

Kennzahl Was sie misst Nutzen im Projekt
Mutation Score Indicator (MSI) Anteil aller erkannten Mutanten am Gesamtbestand Hauptkennzahl für die Qualität der gesamten Test Suite
Mutation Code Coverage Anteil der Mutanten, die überhaupt von Tests berührt werden Vergleichswert zur klassischen Code Coverage
Covered Code MSI MSI nur für Code, der bereits getestet ist Zeigt, wie stark die vorhandenen Assertions wirklich sind
Timeouts Mutanten, die in der Laufzeitgrenze hängen bleiben Hinweis auf Endlosschleifen und auf zu optimistische MSI Werte

Infection in der CI Pipeline

Ein kompletter Mutation Lauf über eine große Codebase dauert. Deshalb gehört Infection im Pull Request nicht auf das ganze Projekt, sondern auf die geänderten Zeilen. Genau dafür gibt es --git-diff-lines.
Code:
          

vendor/bin/infection --git-diff-lines --git-diff-base=origin/main --threads=4

So bekommt jeder Pull Request eine harte Aussage über die neuen Tests, ohne dass die Pipeline Minuten verliert. Den vollständigen Lauf legst du auf einen Nightly Job oder auf den Release Branch und wertest dort den Trend aus.
Code:
          

name: Mutation Testing
on: [pull_request]
jobs:
  infection:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
        with:
          fetch-depth: 0
      - uses: shivammathur/setup-php@v2
        with:
          php-version: '8.4'
          coverage: pcov
      - run: composer install --no-interaction --no-progress
      - run: vendor/bin/infection --git-diff-lines --git-diff-base=origin/main --threads=4 --min-msi=70

Infection ist damit ein Quality Gate wie PHPStan oder GrumPHP. Wie eine komplette Pipeline mit Docker, Staging und Preview URLs aussieht, zeigen wir bei der CI CD Pipeline.

Timeouts ehrlich bewerten seit Infection 0.32.3

Timeouts zählten bei Infection traditionell als getötete Mutanten. Auf schwacher CI Hardware hebt das den MSI künstlich an: Ein Mutant, der lokal entkommen würde, läuft im Build einfach in die Zeitgrenze und sieht dann aus wie ein Erfolg.
Version 0.32.3 brachte im Januar 2026 zwei Optionen gegen dieses Problem. --with-timeouts wertet Timeouts als entkommen und rechnet sie gegen den MSI. --max-timeouts lässt den Build ab einer festen Zahl von Timeouts scheitern, ohne die Kennzahl zu verändern.
Code:
          

infection --with-timeouts --min-msi=80
infection --git-diff-lines --max-timeouts=0

Beide Schalter lassen sich dauerhaft in der Konfiguration setzen.
Code:
          

{
    "timeoutsAsEscaped": true,
    "maxTimeouts": 10,
    "minMsi": 77
}

Für Pull Requests ist eine Null Toleranz Regel sinnvoll. Neue Timeouts kommen selten aus dem Nichts. Meist steckt eine Schleife dahinter, deren Abbruchbedingung kein Test prüft, und das ist exakt die Art von Lücke, für die du Mutation Testing eingeführt hast.

Was ist neu: Infection 0.33 bis 0.35 im Jahr 2026

Infection hat 2026 ein hohes Tempo. Zwischen Mai und August kamen drei Minor Versionen, aktuell ist 0.35.2 vom 19. August 2026. Drei Änderungen betreffen deinen Alltag direkt.
Parallel als Standard. Bis 0.33.1 lief Infection ohne --threads auf einem einzigen Prozess. Seit 0.33.2 wählt das Tool die Zahl der Prozesse selbst. Wer die Option bisher aus Gewohnheit gesetzt hat, kann sie streichen, solange er keinen festen Wert für die CI braucht.
Positional Arguments statt --filter. Mit 0.34.0 hängst du Pfade direkt an den Befehl, auch für config:list-sources. --filter ist als veraltet markiert und sollte in Skripten und Makefiles ersetzt werden.
Code:
          

# alt
vendor/bin/infection --filter=src/Service/Payment.php

# neu ab 0.34.0
vendor/bin/infection src/Service/Payment.php

Neues Testframework Testo. Seit 0.33.0 unterstützt Infection neben PHPUnit, PhpSpec und Codeception auch Testo. In der Konfiguration legst du das über testFramework fest.
Dazu kommen zwei Punkte für Umsteiger. 0.35.0 bricht bewusst mit der Vergangenheit und lässt den Lauf scheitern, wenn PHP eine auto_prepend_file Direktive gesetzt hat. Und 0.35.1 hat die PHAR so gebaut, dass sie unter PHP 8.5 wieder sauber startet. Wer also gerade auf PHP 8.5 geht, sollte mindestens 0.35.1 nutzen.

Infection Releases 2026 im Überblick

Version Datum Wichtigste Änderung
0.32.3 13. Januar 2026 Optionen --with-timeouts und --max-timeouts, neuer JSON Summary Logger
0.33.0 17. Mai 2026 Unterstützung für das Testframework Testo, konfigurierbarer Dots Reporter
0.33.2 20. Mai 2026 Mehrere Prozesse laufen jetzt standardmäßig statt nur einem
0.33.3 18. Juni 2026 Neue Option --test-framework-extra-args, Logger Ausgabe nach php://output
0.34.0 28. Juni 2026 Positional Arguments für die Quellauswahl, --filter ist veraltet
0.34.2 7. August 2026 Anpassung an PHPUnit 13.3, korrekt escapte GitHub Annotations
0.35.0 17. August 2026 BC Break bei gesetztem auto_prepend_file, Fixes für Windows und mago
0.35.2 19. August 2026 Aktuelle Version, Fix der Testreihenfolge bei PHPUnit Defects

Typische Funde in echten Testsuiten

Die überlebenden Mutanten wiederholen sich in fast jedem Projekt. Wer die Muster kennt, liest den Report deutlich schneller.
  • Randbedingungen: Aus einem größer wird ein größer gleich und kein Test merkt es. Der Grenzfall wurde nie geprüft.
  • Fehlende Assertions: Der Test ruft eine Methode auf, prüft aber nur, dass keine Exception fliegt. Entfernt Infection den Methodenrumpf, bleibt alles grün.
  • Rückgabewerte: Eine Methode gibt true statt des berechneten Werts zurück und die Tests laufen weiter durch.
  • Fehlerbehandlung: Catch Blöcke und Exception Pfade sind selten getestet. Mutationen im Error Handling überleben besonders gern.
  • Tote Konfiguration: Mutanten in Code, den niemand aufruft. Hier hilft ein Blick auf Unused Public und Class Leak.
Bei Legacy Code lohnt der umgekehrte Weg. Erst sicherst du das Verhalten mit Characterization Tests ab, dann misst du mit Infection nach, ob diese Tests überhaupt etwas festhalten. Für die anschließende Ablösung alter Teile passt das Strangler Fig Pattern.

Infection zusammen mit statischer Analyse

Manche Mutanten sind gar keine gültigen Programme. Sie brechen Typen oder Verträge und wären in echtem Code nie durch die Analyse gekommen. Solche falschen Treffer kosten Zeit beim Lesen des Reports.
Dagegen gibt es die Static Analysis Integration. Ein Plugin lässt vor der Bewertung eines entkommenen Mutanten noch PHPStan oder Psalm darüber laufen. Was die Analyse ablehnt, zählt nicht mehr gegen deinen MSI.
Code:
          

composer require --dev roave/infection-static-analysis-plugin

Im Zusammenspiel ergibt das eine klare Aufgabenteilung. Statische Analyse prüft, ob der Code stimmig ist. Type Coverage zeigt, wie vollständig die Typen sind. Rector zieht die Modernisierung nach. Und Infection prüft als einziges Werkzeug die Tests selbst. Wie wir diese Gates in Projekten zusammenstellen, steht beim PHP Refactoring und bei der Legacy Modernisierung.

Weiterführende Ressourcen

Offizielle Dokumentation
Installation, Mutatoren, Profile und alle Kommandozeilenoptionen.
https://infection.github.io/guide/
Infection auf GitHub
Quellcode, Issues, Releases und die Diskussionen des Teams rund um Maks Rafalko.
https://github.com/infection/infection
Infection Playground
Mutation Testing im Browser ausprobieren, ohne etwas zu installieren.
https://infection-php.dev/

Do not use Xdebug for collecting code coverage unless you need a path/branch coverage

Maks Rafalko, Creator of Infection – maks-rafalko.github.io

NCA Erfahrung mit Mutation Testing in PHP Projekten

Mutation Testing ist kein Einstiegswerkzeug. Es zeigt seinen Wert erst, wenn die Basis steht: laufende PHPUnit Tests, saubere Functional Tests und eine Pipeline, die bei Rot auch wirklich stoppt. Wir bauen diese Reihenfolge in Projekten auf und hängen Infection als letzte Stufe dahinter.
Rund um Testing und Codequalität findest du im Glossar die passenden Bausteine: PEST als alternative Testsyntax, Paratest für parallele Läufe, Symfony KernelTestCase für Integrationstests, GrumPHP als Wächter vor dem Commit, Easy Coding Standard für einheitlichen Stil und Deptrac für die Architekturgrenzen.
Wer tiefer einsteigen will, liest weiter bei Patch Coverage, PHP Metrics, PHP Insights und ISTQB. Den kompletten Überblick gibt das NCA PHP Glossar mit allen Werkzeugen für Qualität in PHP Projekten.
CYPRESS.IO Ambassador und IT Consultant für QA Engenieering und Qualität in PHP Projekten.

Erreichen Sie unsere PHP Consultant Spezialisten

Wir sind Experten für PHP und helfen Ihnen, Ihre digitalen Herausforderungen zu meistern. Unser erfahrenes Team unterstützt Sie bei PHP Updates, PHP Refactoring und berät Sie remote zu allen Fragen rund um PHP. Mit unseren vollautomatischen CI/CD Deployments und einer robusten Docker-Infrastruktur bringen wir Ihre PHP-Projekte auf das nächste Level. Vertrauen Sie auf unsere Expertise für zuverlässige und skalierbare PHP-Lösungen.

Häufige Fragen zum Infection Framework

Die wichtigsten Fragen aus Projekten, Workshops und Meetups zu Mutation Testing mit Infection.

Was ist das Infection Framework 2026?

Infection ist das Mutation Testing Framework für PHP. Es verändert deinen Quellcode an vielen kleinen Stellen und führt nach jeder Änderung die Tests aus, die diese Zeile abdecken. Bleiben die Tests grün, hat der Mutant überlebt und die Testsuite hat eine Lücke. Die Arbeit läuft auf dem Abstract Syntax Tree, nicht auf reiner Textersetzung.

Welche Infection Version ist 2026 aktuell?

Aktuell ist 0.35.2 vom 19. August 2026. Das Jahr brachte drei Minor Versionen: 0.33 mit Unterstützung für das Testframework Testo, 0.34 mit Positional Arguments anstelle von --filter und 0.35 mit einem BC Break bei gesetztem auto_prepend_file. Seit 0.33.2 arbeitet Infection außerdem ohne weitere Angabe schon parallel.

Welche PHP Version braucht Infection 2026?

Aktuelle Infection Versionen brauchen PHP 8.3 oder neuer. Dazu kommt ein Coverage Treiber: Xdebug, phpdbg oder pcov. Für ältere PHP Versionen gibt es ältere Infection Releases, die Zuordnung steht als Tabelle in der offiziellen Installationsdokumentation. Wer auf PHP 8.5 arbeitet, nutzt mindestens die PHAR aus Version 0.35.1.

Was kostet Infection 2026?

Infection ist freie Open Source Software unter der BSD-3-Clause Lizenz. Für die Nutzung fallen keine Lizenzkosten an, weder lokal noch in der Pipeline. Das Projekt finanziert sich über GitHub Sponsors. Der tatsächliche Aufwand liegt woanders: in der Rechenzeit der Pipeline und in der Arbeit, die überlebenden Mutanten auch wirklich zu bearbeiten.

Wie unterscheidet sich Mutation Testing 2026 von Code Coverage?

Code Coverage misst, welche Zeilen beim Testlauf ausgeführt werden. Mutation Testing misst, ob deine Tests bei einem Fehler in diesen Zeilen auch rot werden. Eine Datei kann 100 Prozent Coverage haben und trotzdem keine einzige sinnvolle Assertion enthalten. Genau diese Lücke zwischen Ausführung und Prüfung macht der Mutation Score Indicator sichtbar.

Welchen MSI Wert sollte ein PHP Projekt erreichen?

Es gibt keinen allgemeingültigen Zielwert. Sinnvoll ist der Wert, den dein Projekt heute erreicht, als Startschwelle in der Konfiguration. Von dort ziehst du minMsi in kleinen Schritten an, damit die Pipeline nicht dauerhaft rot steht. Aussagekräftiger als der reine MSI ist oft der Covered Code MSI, weil er ungetesteten Code ausblendet.

Funktioniert Infection ohne bestehende Unit Tests?

Nein. Infection bewertet vorhandene Tests und kann ohne sie nichts messen. Ohne Testsuite gibt es keine Coverage Daten und damit auch keine Mutanten, die geprüft werden könnten. Der erste Schritt ist also eine laufende Testsuite. Bei Legacy Code sind Characterization Tests der übliche Einstieg, danach zeigt Infection, wie belastbar sie sind.

Welche Test Frameworks unterstützt Infection?

Infection arbeitet mit PHPUnit, PhpSpec, Codeception und seit Version 0.33.0 auch mit Testo zusammen. Die PHAR Distribution bringt alle offiziell unterstützten Adapter bereits mit. Bei der Composer Installation kommen die Adapter über den Extension Installer dazu und werden automatisch erkannt. In der Konfiguration legst du mit testFramework fest, welches Framework verwendet wird.

Wie lange dauert ein kompletter Mutation Lauf?

Deutlich länger als ein normaler Testlauf, weil für jeden Mutanten die abdeckenden Tests erneut starten. Seit 0.33.2 nutzt Infection von sich aus mehrere Prozesse, das nimmt einiges an Laufzeit. Weitere Hebel sind vorhandene Coverage Daten aus dem regulären Testlauf und eine Beschränkung auf die geänderten Zeilen.

Wie integriere ich Infection in GitHub Actions?

Im Pull Request läuft Infection mit --git-diff-lines nur auf den geänderten Zeilen und mit --min-msi als Abbruchkriterium. Wichtig sind zwei Dinge im Workflow: die volle Git History über fetch-depth 0 und ein aktivierter Coverage Treiber wie pcov. Den vollständigen Lauf legst du auf einen Nightly Job oder den Release Branch.

Was bedeutet ein entkommener Mutant?

Ein entkommener Mutant ist eine Codeänderung, die keine Testfehler ausgelöst hat. Der Report zeigt sie als Diff gegen das Original. Jede dieser Stellen ist ein konkreter Hinweis: Entweder fehlt eine Assertion, oder der Code ist überflüssig. Beide Antworten sind wertvoll, denn sie führen zu besseren Tests oder zu weniger Code.

Was bringen die Optionen mit Timeouts?

Timeouts zählten bisher wie getötete Mutanten und haben den MSI auf langsamer CI Hardware geschönt. Mit --with-timeouts werden sie als entkommen gewertet und drücken den Score auf einen ehrlichen Wert. Mit --max-timeouts setzt du eine harte Obergrenze, ab der der Build scheitert. Beide Schalter lassen sich auch in der Konfiguration hinterlegen.

Welche Alternativen zu Infection gibt es?

Für PHP ist Infection der De-facto-Standard. Der Vorgänger Humbug wurde zugunsten von Infection eingestellt. In anderen Sprachen gibt es vergleichbare Werkzeuge wie PIT für Java oder Stryker für JavaScript und .NET. Ergänzend statt alternativ arbeiten statische Analysewerkzeuge wie PHPStan und Psalm, die andere Fehlerklassen finden.

Wie starte ich Infection in einem großen Legacy Projekt?

Nicht mit einem Komplettlauf. Häng den Pfad eines Moduls direkt an den Befehl oder nutze --git-diff-lines für die Änderungen im Branch. So bekommst du in Minuten ein Ergebnis statt in Stunden. Erst wenn die Quality Gates stehen und die Testsuite stabil läuft, lohnt der vollständige Durchlauf im Nightly Job.