Die Anfrage klingt fast immer gleich: Ein PHP-System läuft seit acht, zehn, manchmal fünfzehn Jahren. Es soll auf eine neue PHP-Version, in ein Framework oder auf frische Infrastruktur umziehen. Und dann kommt der Satz, der jedes Migrationsprojekt gefährlich macht: "Tests haben wir keine."
Das ist kein Vorwurf. Die wenigsten gewachsenen Anwendungen wurden testgetrieben gebaut. Aber es verändert alles daran, wie eine Migration ablaufen muss. Denn ohne Tests migrieren Sie nicht ein bekanntes System – Sie migrieren eine Vermutung.
Warum eine Migration ohne Tests so gefährlich ist
Der Kern des Problems: Bei einer Migration ändern Sie den Code drumherum, nicht die Fachlogik. PHP 7 zu 8.3, mysql_* zu PDO, ein selbstgebautes Framework zu Symfony. Bei jedem dieser Schritte verschiebt sich Verhalten an Stellen, die niemand auf dem Schirm hat.
Ein paar konkrete Fallen, die in der Praxis regelmäßig zuschlagen:
- Typ-Vergleiche. PHP 8 hat das Verhalten von
0 == "foo"geändert. Frühertrue, heutefalse. Wenn Ihr alter Code sich darauf verlässt, kippt Logik lautlos – kein Fehler, nur ein falsches Ergebnis. - Implizite Float-zu-Int-Umwandlung wirft in PHP 8.1 eine Deprecation, in späteren Versionen einen Fehler. Rundungslogik in Rechnungen oder Preisen ist genau die Stelle, an der das wehtut.
- Sortierung.
usortist seit PHP 8 stabil. Wer sich unbewusst auf die alte, instabile Reihenfolge verlassen hat, sieht plötzlich andere Ausgaben. - Datenbanktreiber. Der Wechsel von mysql_ auf PDO oder mysqli ändert, wie NULL, leere Strings und Zahlen aus der DB zurückkommen.
Keine dieser Änderungen produziert einen Absturz, den Sie sofort bemerken. Sie produzieren falsche Rechnungen, verschwundene Datensätze, kaputte Berechtigungen – und das oft erst Wochen später im Produktivbetrieb. Ohne Tests bemerken Sie es überhaupt nur, wenn ein Kunde sich beschwert.
Das eigentliche Missverständnis: Das alte System ist nicht das Problem
Ein System, das seit Jahren läuft, ist kein Müll. Es ist der Beweis, dass die Fachlogik funktioniert. Tausende Bestellungen, Buchungen oder Abrechnungen sind korrekt durchgelaufen. Dieses Wissen steckt im Code – meist unkommentiert, aber es steckt drin.
Das Problem ist fast nie die Fachlogik. Das Problem ist der Code drumherum: globale Zustände, vermischte Präsentations- und Geschäftslogik, direkte SQL-Strings in Templates, fehlende Abstraktion. Genau dieser Umstand macht das Testen schwer – und verleitet Teams dazu, ganz darauf zu verzichten oder gleich neu zu schreiben.
Neuentwicklung ist in den meisten Fällen die teuerste und riskanteste Option. Sie werfen funktionierende Logik weg und bauen sie aus dem Gedächtnis neu – inklusive aller Sonderfälle, an die sich niemand mehr erinnert. Genau diese Sonderfälle sind es, die produktiv seit Jahren still ihren Dienst tun.
Was PHP Migration Tests konkret leisten müssen
Wozu braucht man Tests bei einer PHP-Migration überhaupt? PHP Migration Tests fixieren das aktuelle Verhalten des Systems, bevor Sie etwas ändern. Sie sind das Sicherheitsnetz, das Ihnen sagt: "Nach dem Umbau verhält sich das System noch genauso wie vorher."
Wichtig ist der Unterschied zwischen zwei Testarten. Klassische Unit-Tests prüfen, ob Code korrekt nach Spezifikation arbeitet. Für eine Migration brauchen Sie oft etwas anderes: Characterization Tests (auch Golden-Master-Tests). Diese prüfen nicht, ob das Verhalten richtig ist, sondern ob es gleich bleibt.
Das ist ein entscheidender Punkt bei Legacy-Code. Sie wollen bei einer Migration keine Bugs fixen. Ein alter Bug, auf den sich vielleicht andere Teile verlassen, gehört erst einmal konserviert – behoben wird er später, bewusst und getrennt. Ein Characterization Test hält genau das fest, was das System heute tut, Macken inklusive.
Wie testet man Code, der nie zum Testen gebaut wurde?
Kann man ein System absichern, das nie Tests hatte? Ja – aber nicht von innen, sondern von außen. Bei stark verwobenem Legacy-Code sind Unit-Tests auf einzelne Klassen oft unmöglich, ohne den Code vorher umzubauen. Und Umbauen ohne Netz ist genau das, was wir vermeiden wollen. Der Ausweg führt über die Ränder.
- Charakterisieren Sie von außen. Schreiben Sie HTTP-Level-Tests: Request rein, komplette Response raus, festgehalten als Referenz. Werkzeuge wie Symfony BrowserKit, Panther oder simple Integrationstests gegen echte Endpunkte funktionieren, ohne dass Sie eine einzige Klasse anfassen.
- Nutzen Sie echte Produktionsdaten als Grundlage. Nehmen Sie eine anonymisierte Kopie realer Eingaben und zeichnen Sie die aktuellen Ausgaben als Golden Master auf. Diese Fälle decken Sonderpfade ab, die sich niemand ausdenken würde.
- Sichern Sie die kritischen Pfade zuerst. Sie brauchen keine 90 Prozent Coverage. Sie brauchen die drei bis fünf Abläufe, deren Fehlverhalten richtig teuer wäre: Bezahlung, Rechnungsstellung, Login und Rechteprüfung, Datenexport.
- Migrieren Sie erst danach – in kleinen Schritten. Nach jedem Schritt laufen die Golden-Master-Tests. Weicht eine Ausgabe ab, wissen Sie sofort, welche Änderung es war, statt nach dem Go-live im Dunkeln zu suchen.
Die ehrliche Reihenfolge einer sicheren Migration
Die verlockende Reihenfolge lautet: erst migrieren, dann testen, wenn Zeit bleibt. Sie ist der häufigste Grund für teure Migrationen, weil jeder Fehler erst spät und mühsam auffällt.
Die belastbare Reihenfolge ist die umgekehrte: Erst das Ist-Verhalten festhalten, dann migrieren, dann verifizieren. Der Aufwand für die Tests kommt vorne rein – und zahlt sich in jedem einzelnen Migrationsschritt danach aus. Sie tauschen ein diffuses Restrisiko im Produktivbetrieb gegen kalkulierbare Arbeit vorab.
Tests bei einer Migration sind keine Qualitätskür. Sie sind das Messgerät, mit dem Sie überhaupt beurteilen können, ob die Migration geglückt ist.
Praxis-Tipp zum Schluss
Wenn Sie vor einer Migration ohne Tests stehen, fangen Sie nicht mit der PHP-Version an, sondern mit einem einzigen Golden-Master-Test für Ihren wichtigsten Ablauf. Zeichnen Sie für zehn reale Eingaben die aktuelle Ausgabe auf und legen Sie sie als Referenz ab. Dieser eine Test kostet Sie einen halben Tag – und er verändert sofort, wie sicher sich jeder folgende Umbauschritt anfühlt. Von dort aus arbeiten Sie sich zu den nächsten kritischen Pfaden vor, statt zu versuchen, alles auf einmal abzudecken.
Genau bei diesem Vorgehen – funktionierende Altsysteme absichern und ohne Blindflug modernisieren – unterstützt LegacyWerk, wenn Sie an einem Punkt nicht allein weiterkommen.