Mutation Testing in PHP: Wie man Tests schreibt, die wirklich Fehler finden

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Warum ist 100% Code Coverage eine Illusion?

\n

Haben Sie sich jemals über einen PHPUnit-Bericht gefreut, in dem „Code Coverage: 98%“ stand? Und dann haben Sie ein Release ausgerollt, und in der Produktion trat ein kritischer Fehler auf. Kommt Ihnen bekannt vor? Das Problem ist, dass die klassische Abdeckung (Line/Statement Coverage) nur misst, welche Codezeilen ausgeführt wurden. Sie prüft nicht, ob Ihre Tests die Logik tatsächlich überprüfen.

\n

Stellen Sie sich vor, Sie schreiben einen Test, der prüft, ob eine Funktion true zurückgibt. Die Funktion selbst gibt aber immer true zurück, selbst wenn man sie kaputt macht. Der Test wird bestanden, die Abdeckung beträgt 100%, aber den Fehler werden Sie nicht finden. Genau hier kommt Mutation Testing in PHP ins Spiel – eine Technik, die das herkömmliche Verständnis von Testen auf den Kopf stellt.

\n

In diesem Artikel werden wir uns ansehen, was Mutationstests sind, wie sie anhand von echtem PHP-Code funktionieren und wie Sie sie mit der Bibliothek Infection in Ihr Projekt integrieren können.

\n\n

Was ist Mutation Testing? (Und warum es keine Magie ist)

\n

Mutation Testing (oder Mutationstests) ist eine Methode zur Bewertung der Testqualität, bei der kleine, absichtliche Änderungen (Mutationen) am Quellcode vorgenommen werden. Wenn der Test nach der Änderung fehlschlägt – ist der Mutant getötet, der Test funktioniert. Wenn der Test grün bleibt – hat der Mutant überlebt, was bedeutet, dass Ihr Test nichts überprüft.

\n

Eine einfache Analogie: Sie sind ein Wachmann, Ihre Tests sind Kameras. Das Mutation Testing schickt „Eindringlinge“ (Mutanten) ins Gebäude. Wenn die Kamera (der Test) den Eindringling bemerkt – funktioniert sie. Wenn der Eindringling ungestört herumläuft – ist die Kamera nutzlos.

\n

In PHP ist das wichtigste Werkzeug dafür Infection – eine Bibliothek, die PHPUnit für jeden Mutanten ausführt und die Ergebnisse analysiert.

\n\n

Wie sieht das in der Praxis aus?

\n

Angenommen, Sie haben eine einfache Rechner-Klasse:

\n
<?php\nclass Calculator\n{\n    public function add(int $a, int $b): int\n    {\n        return $a + $b;\n    }\n}
\n

Und einen dazugehörigen Test:

\n
<?php\nuse PHPUnit\\Framework\\TestCase;\n\nclass CalculatorTest extends TestCase\n{\n    public function testAdd()\n    {\n        $calc = new Calculator();\n        $result = $calc->add(2, 3);\n        $this->assertEquals(5, $result);\n    }\n}
\n

Das Tool Infection erstellt einen Mutanten, indem es + durch - ersetzt:

\n
return $a - $b;
\n

Dann führt es den Test aus. Wenn der Test fehlschlägt – ist der Mutant getötet. Wenn der Test bestanden wird (und er wird bestanden, weil Sie nur 2+3 und nicht 2-3 prüfen) – hat der Mutant überlebt. Das ist ein Signal: Ihr Test ist nicht gut genug.

\n\n

Installation von Infection und erster Start

\n

Zunächst installieren wir Infection über Composer:

\n
composer require --dev infection/infection
\n

Dann erstellen wir eine Konfigurationsdatei infection.json (oder führen Sie vendor/bin/infection für die interaktive Einrichtung aus).

\n

Beispiel einer minimalen Konfiguration:

\n
{\n    "source": {\n        "directories": [\n            "src"\n        ]\n    },\n    "phpUnit": {\n        "configDir": "."\n    },\n    "mutators": {\n        "@default": true\n    }\n}
\n

Starten Sie das Mutation Testing:

\n
vendor/bin/infection --min-msi=100
\n

Wobei --min-msi=100 bedeutet, dass wir möchten, dass 100% der Mutanten getötet werden (ein idealer, aber selten erreichbarer Wert). Infection erstellt einen Bericht im HTML-Format (Ordner infection.html), in dem überlebende Mutanten rot markiert sind.

\n\n

Arten von Mutationen in PHP (mit Beispielen)

\n

Infection unterstützt Dutzende von Mutatoren. Hier sind die häufigsten, denen Sie begegnen werden:

\n\n

1. Mathematische Operatoren

\n

Ersetzung von + durch -, * durch /, % durch * usw.

\n
// Ursprünglicher Code\nreturn $price * $quantity;\n\n// Mutant\nreturn $price / $quantity;

Blogs

Buchempfehlungen