Testabdeckung sinnvoll priorisieren (keine 100-%-Dogmatik)
Testabdeckung sinnvoll priorisieren (keine 100-%-Dogmatik)
~6 Min. Lesezeit Zuletzt aktualisiert am 9. August 2026
PHPUnits Coverage-Report (mit Xdebug oder PCOV als Treiber) beantwortet eine einzige, sehr präzise Frage: welche Codezeile wurde während der Testläufe wenigstens einmal ausgeführt. Er beantwortet keine andere, viel wichtigere Frage: ob diese Ausführung auch etwas Sinnvolles geprüft hat. Eine Zeile kann zu 100 % "abgedeckt" sein und trotzdem völlig ungetestet bleiben, wenn der Test keine Assertion dazu enthält.
bin/cli vendor/bin/phpunit -c dev/tests/unit/phpunit.xml.dist \
--coverage-html var/coverage/loyalty \
app/code/Mironsoft/Loyalty/Test/UnitWas in diesem Modul hohe Priorität verdient
- Geld- und Punkte-Arithmetik:
PointsCalculator::calculatePoints()/determineTier()(Kapitel 5/91) - jeder Fehler wirkt sich direkt auf reale Kundenguthaben aus. - Reconciliation-Logik: die "was müsste gebucht sein, minus was bereits gebucht wurde"-Arithmetik in
ReversePointsOnCreditmemoSave(Kapitel 31) undExpirePoints(Kapitel 33) - genau die Stellen, an denen ein Vorzeichenfehler unbemerkt Punkte doppelt abzieht oder gutschreibt. - Idempotenz- und Guard-Bedingungen: die beiden Prüfungen aus Kapitel 92 - ein einziger vergessener Guard bedeutet doppelt vergebene Punkte bei jedem erneuten Event-Dispatch.
- Sicherheitsrelevanter Code:
RedemptionRateLimiter(Kapitel 86), ACL-Prüfungen, die Guest-vs-Customer-Unterscheidung in GraphQL-Resolvern (Kapitel 82/83).
Was bewusst niedrige Priorität hat
- Reine Getter/Setter-Ketten: die generierten Accessor-Methoden von
Api\Data\RewardInterface(Kapitel 79) - keine Logik, kein Verzweigungspunkt, nichts, was ein Test aufdecken könnte, das der PHP-Typprüfer nicht ohnehin schon garantiert. - Dünne Controller/Resolver-Wrapper: Controller, die nur eine Zeile lang an einen bereits getesteten Service Contract delegieren (Kapitel 79-83) - der Wert liegt im Service dahinter, nicht im Delegations-Einzeiler.
- Alpine.js/phtml-Templates: das
customer-data/points-badge.phtml-Template aus Kapitel 84 - PHPUnit prüft PHP, kein clientseitiges JavaScript; dafür wäre ein völlig anderes Werkzeug nötig, das dieses Modul bewusst nicht einführt.
Tipp: Eine nützliche Faustfrage vor jedem neuen Test: "Welcher konkrete, reale Fehler würde diesen Test fehlschlagen lassen?" Fällt die Antwort schwer, ist der Test vermutlich reine Zeilenabdeckung ohne echten Wert - genau das Muster, das eine 100-%-Vorgabe systematisch erzeugt, weil sie auch für Zeilen ohne jede Verzweigung einen Test verlangt.
Achtung: Kapitel 92 hat bewusst nur zwei von mehreren möglichen Pfaden durch AwardPointsOnOrderPlaced::awardPoints() getestet - die beiden frühen Ausstiege. Der komplette Happy Path mit mehreren Bestellpositionen, unterschiedlichen Multiplikatoren und einem tatsächlichen Ledger-Eintrag wurde Kapitel 93 als Integrationstest zugewiesen, nicht als drittes, viertes und fünftes gemocktes Unit-Test-Szenario nachgebaut. Eine bewusste, dokumentierte Lücke ist etwas anderes als eine vergessene.
Teamvereinbarung statt Werkzeug-Vorgabe
Ein Coverage-Schwellenwert in der CI-Pipeline (Kapitel 95 zeigt, wie er dort erzwungen werden kann) ist am sinnvollsten als Untergrenze gegen Rückschritt - "die Abdeckung darf nicht sinken" -, nicht als Ziel an sich. Ein Team, das 100 % anstrebt, verbringt am Ende Zeit mit Tests für Api\Data-Interfaces, statt mit genau den Reconciliation- und Guard-Tests, die tatsächlich reale Fehler verhindern.
Kapitel 95 nimmt diese Tests - und den Coverage-Report selbst - und automatisiert sie: Continuous Integration.