Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

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/Unit

Was 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) und ExpirePoints (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.