@test
assert
PHPUnit · Integration Tests · MFTF · Test-Pyramide · Magento 2
Die Magento 2 Test-Pyramide
was Unit, Integration und MFTF jeweils leisten

Die häufigste Fehlinvestition in der Testautomatisierung: zu viele langsame End-to-End-Tests und zu wenige schnelle Unit-Tests. Die Test-Pyramide gibt die richtige Gewichtung vor – drei Stufen mit klar getrennten Aufgaben, die zusammen eine zuverlässige Teststrategie ergeben.

18 Min. Lesezeit Unit · Integration · MFTF · CI/CD · Testabdeckung Magento 2.4 · PHPUnit 10 · MFTF 3.x

1. Das Konzept der Test-Pyramide für Magento

Die Test-Pyramide ist ein Modell, das die Verteilung von Tests nach Geschwindigkeit, Isolationsgrad und Infrastrukturaufwand beschreibt. An der Basis stehen viele schnelle Unit-Tests, in der Mitte weniger Integrationstests, an der Spitze wenige End-to-End-Tests. Für Magento 2 bedeutet das konkret: Unit-Tests mit PHPUnit ohne Bootstrap, Integrationstests mit vollem Magento-Bootstrap und Datenbankzugang, MFTF-Tests mit Browser-Automatisierung gegen eine vollständige Magento-Installation.

Das Modell ist kein Dogma, sondern eine Orientierung. In Magento-Projekten, die stark datenbankgetrieben sind, verschiebt sich der Schwerpunkt etwas in Richtung Integrationstests – weil viele Kernfunktionen nur mit echten Datenbankoperationen sinnvoll getestet werden können. Trotzdem bleibt die Grundregel: schnelle, isolierte Tests dominieren die Basis, langsame, infrastrukturintensive Tests bleiben an der Spitze.

Ein häufiger Fehler in Magento-Projekten ist das Fehlen einer expliziten Teststrategie. Tests entstehen ad hoc, meistens als Integrations- oder MFTF-Tests, weil sie die sichtbaren Ergebnisse direkt prüfen. Das Ergebnis ist eine umgekehrte Pyramide – viele langsame Tests, die bei jedem Merge mehrere Minuten laufen, und keine Unit-Tests, die in Sekunden Feedback geben. Die Test-Pyramide gibt das richtige Gegengewicht vor.

2. Unit-Tests: die Basis der Pyramide

Unit-Tests in Magento 2 laufen unter dev/tests/unit/ mit einem minimalen Bootstrap, der nur den Autoloader aktiviert. Alle Abhängigkeiten der getesteten Klasse werden durch PHPUnit-Mocks ersetzt. Das Ergebnis: eine Test-Suite mit hundert Tests, die in unter fünf Sekunden durchläuft – ohne Datenbankverbindung, ohne Magento-Instanz, ohne Browser. Dieser Geschwindigkeitsvorteil ist der Hauptgrund, warum Unit-Tests die Basis der Pyramide bilden.

Was Unit-Tests in Magento abdecken: die Logik von ViewModels, Services und Helpers, Exception-Handling in Repositories, Berechnungslogik in Preis-Modellen, Validierungsregeln in Data-Transfer-Objects. Was sie nicht abdecken: Datenbankinteraktionen, Event-Dispatching mit echten Observern, Layout-Rendering, Session-Handling. Diese klare Grenze ist wichtig – wer sie missachtet und Datenbankoperationen im Unit-Test mocken will, baut Mocks, die die echte Implementierung nur vortäuschen.

<?php
// File: dev/tests/unit/phpunit.xml (relevant excerpt)
// Unit tests: no database, no full Magento bootstrap
// Run: vendor/bin/phpunit -c dev/tests/unit/phpunit.xml \
//      --testsuite=Mironsoft_Catalog

// Typical unit test execution time: < 5 seconds for 100 tests
// Coverage: business logic, exception handling, calculation logic

// Integration test phpunit.xml is at: dev/tests/integration/phpunit.xml
// Integration tests require: running database, Magento install, fixtures
// Typical execution time: 30 seconds to several minutes

// MFTF: dev/tests/acceptance/
// Requires: full Magento stack, Selenium/WebDriver, browser
// Typical execution time: minutes per scenario

// The ratio in a healthy Magento project:
// Unit: 70% of all tests
// Integration: 25% of all tests
// MFTF/E2E: 5% of all tests (critical user journeys only)

3. Integrationstests: das Zusammenspiel prüfen

Magento-Integrationstests unter dev/tests/integration/ verwenden einen vollständigen Bootstrap mit eigener Test-Datenbank und aktivem DI-Container. Sie testen, ob Klassen im echten Magento-Kontext korrekt zusammenarbeiten: ob ein Repository wirklich die richtigen Einträge aus der Datenbank liest, ob ein Plugin den Methodenaufruf korrekt modifiziert, ob ein Observer nach einem Event den erwarteten Seiteneffekt erzeugt. Das ist die Teststufe, die Dinge aufdeckt, die Unit-Tests mit Mocks verbergen.

Integrationstests in Magento nutzen Fixtures – PHP-Skripte, die Testdaten in die Datenbank schreiben und nach dem Test wieder entfernen. Das @magentoDataFixture-Attribut verweist auf diese Fixture-Datei und stellt sicher, dass der Test in einem definierten Datenbankzustand läuft. Dieser Mechanismus macht Integrationstests wiederholbar und isoliert voneinander, auch wenn sie gegen dieselbe Datenbank laufen. Der Nachteil: jeder Datenbankzugriff kostet Zeit, was Integrationstests um Größenordnungen langsamer als Unit-Tests macht.

<?php
// File: app/code/Mironsoft/Catalog/Test/Integration/Model/ProductRepositoryTest.php
declare(strict_types=1);

namespace Mironsoft\Catalog\Test\Integration\Model;

use Magento\TestFramework\Helper\Bootstrap;
use Magento\Framework\Exception\NoSuchEntityException;
use Mironsoft\Catalog\Api\ProductRepositoryInterface;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Attributes\Test;

/**
 * Integration test: uses real database, real DI container.
 * Fixture creates test product before each test, rolls back after.
 */
class ProductRepositoryTest extends TestCase
{
    private ProductRepositoryInterface $repository;

    protected function setUp(): void
    {
        $objectManager = Bootstrap::getObjectManager();
        $this->repository = $objectManager->get(ProductRepositoryInterface::class);
    }

    #[Test]
    #[\Magento\TestFramework\Annotation\DataFixture(
        'Mironsoft_Catalog::Test/Integration/_files/product_enabled.php'
    )]
    public function getByIdReturnsRealProductFromDatabase(): void
    {
        // This test actually queries the database — no mocks
        $product = $this->repository->getById(1);
        $this->assertSame('test-product-sku', $product->getSku());
        $this->assertTrue((bool)$product->getStatus());
    }

    #[Test]
    public function getByIdThrowsExceptionForNonExistentId(): void
    {
        $this->expectException(NoSuchEntityException::class);
        $this->repository->getById(99999);
    }
}

4. MFTF: End-to-End im Browser

Das Magento Functional Testing Framework (MFTF) automatisiert Browser-Tests gegen eine vollständige Magento-Installation. MFTF-Tests simulieren echte Nutzerinteraktionen: Produkt in den Warenkorb legen, Checkout durchführen, Admin-Panel navigieren, Formulare ausfüllen. Sie prüfen das Gesamtsystem aus Nutzerperspektive und decken Integrationsbrüche auf, die weder Unit- noch Integrationstests finden können – zum Beispiel wenn ein JavaScript-Fehler den Checkout-Button deaktiviert.

MFTF-Tests sind in XML geschrieben und folgen dem Page-Object-Pattern. Jede Seite hat eine XML-Datei, die die Selektoren definiert, und jeder Test beschreibt die Schritte als XML-Actions. Das klingt nach viel Overhead, hat aber einen Vorteil: MFTF-Tests können von QA-Mitarbeitern ohne PHP-Kenntnisse geschrieben und angepasst werden. Der Nachteil ist die Ausführungsgeschwindigkeit – ein einziger MFTF-Test kann Minuten dauern, weil er auf Seitenladungen, JavaScript-Ausführung und Browser-Rendering wartet.

5. Das richtige Verhältnis der Teststufen

Eine gesunde Testpyramide für ein Magento-Custommodul hat ungefähr dieses Verhältnis: 70% Unit-Tests, 25% Integrationstests, 5% MFTF-Tests. Das bedeutet in der Praxis: jede Methode mit nichttrivialer Logik bekommt einen Unit-Test, kritische Datenbankoperationen bekommen einen Integrationstest, und die wichtigsten Nutzer-Journeys – Checkout, Login, Produktsuche – bekommen einen MFTF-Test.

Dieses Verhältnis ist kein absolutes Gesetz. Ein Modul, das primär Datenmigration durchführt, braucht mehr Integrationstests als ein Modul, das nur Preisberechnungen implementiert. Ein Modul, das komplexe Frontend-Interaktionen steuert, braucht mehr MFTF-Tests als ein reines Backend-Modul. Die Test-Pyramide ist das Ziel, die tatsächliche Gewichtung hängt vom Modultyp ab. Was immer gilt: MFTF-Tests sind am teuersten in Erstellung und Wartung und sollten die Ausnahme bleiben.

6. Infrastrukturaufwand pro Teststufe

Unit-Tests benötigen nur PHP, Composer und PHPUnit – sie laufen in jeder Umgebung, die einen PHP-Interpreter hat. Integrationstests benötigen eine vollständige Magento-Datenbank (typischerweise eine separate Test-Datenbank) und einen Magento-Install ohne aktive Caches. MFTF-Tests benötigen zusätzlich einen Browser-Treiber (Chrome + ChromeDriver oder Selenium Grid), eine vollständige Magento-Installation mit aktivem Frontend und MFTF-Konfiguration in .env.testing.

In einer Docker-basierten Entwicklungsumgebung wie Mark Shust's Setup laufen Unit-Tests und Integrationstests direkt im PHP-Container. MFTF-Tests erfordern zusätzliche Container für Selenium. Das erhöht den Infrastrukturaufwand spürbar – sowohl lokal als auch in der CI-Pipeline. Dieser Aufwand rechtfertigt sich nur für die kritischsten End-to-End-Szenarien.

7. Test-Pyramide in der CI/CD-Pipeline

In einer gut konfigurierten CI-Pipeline laufen die drei Teststufen gestaffelt: Unit-Tests laufen bei jedem Commit und geben innerhalb von Sekunden Feedback. Integrationstests laufen bei jedem Pull-Request-Merge gegen den Hauptbranch und geben innerhalb von Minuten Feedback. MFTF-Tests laufen einmal täglich oder vor einem Release und geben innerhalb von zehn bis dreißig Minuten Feedback. Diese Staffelung stellt sicher, dass Entwickler schnelles Feedback für alltägliche Änderungen bekommen und die teuren Tests nicht den Entwicklungsfluss verlangsamen.

Eine typische GitHub-Actions-Konfiguration für Magento hat separate Jobs für die drei Teststufen. Der Unit-Test-Job läuft parallel zum Linting und PHPStan. Der Integrations-Test-Job startet erst, wenn der Unit-Test-Job erfolgreich war – als Gate. Der MFTF-Job läuft nur auf dem Hauptbranch oder auf Release-Branches. Dieses Setup gibt den Entwicklern täglich produktives Feedback, ohne die CI-Pipeline mit langen Wartezeiten zu blockieren.

8. Anti-Patterns: die umgekehrte Pyramide

Das häufigste Anti-Pattern in Magento-Projekten ist die umgekehrte Pyramide: viele MFTF-Tests, wenige Integrationstests, keine Unit-Tests. Das entsteht oft, weil MFTF-Tests sichtbare Ergebnisse prüfen und leicht zu verstehen sind – der Tester sieht im Video, wie der Bot durch den Checkout navigiert. Unit-Tests dagegen testen abstrakte Logik und erfordern ein gutes Verständnis der Klassen. Der Preis für die umgekehrte Pyramide ist eine CI-Pipeline, die dreißig Minuten läuft und bei jedem flaky MFTF-Test falsch-negativ schlägt.

Ein zweites Anti-Pattern ist der übermäßige Einsatz von Integrationstests für Logik, die sich mit Unit-Tests abdecken ließe. Wenn ein Entwickler jeden Service mit einem Integrationstest prüft, weil er sich nicht mit Mocking beschäftigen will, entstehen langsame Tests, die bei Datenbankfehlern scheitern, ohne dass sich die Geschäftslogik geändert hat. Das untergräbt das Vertrauen in die Test-Suite.

Kriterium Unit-Test Integrationstest MFTF
Ausführungszeit Millisekunden Sekunden Minuten
Infrastrukturbedarf Nur PHP + PHPUnit DB + Magento Browser + volles Stack
Flakiness-Risiko Sehr gering Mittel Hoch
Abgedeckter Bereich Logik einer Klasse Modul + Datenbank Gesamtes System
Wartungsaufwand Gering Mittel Hoch

10. Zusammenfassung

Die Magento 2 Test-Pyramide beschreibt, wie Unit-Tests, Integrationstests und MFTF-Tests zueinander stehen und welche Aufgabe jede Stufe hat. Unit-Tests bilden die breite Basis: schnell, isoliert, ohne Infrastruktur. Integrationstests prüfen das Zusammenspiel mit Datenbank und DI-Container. MFTF-Tests prüfen kritische Nutzer-Journeys im Browser. Das optimale Verhältnis ist 70% Unit, 25% Integration, 5% MFTF – je nach Modultyp mit Verschiebungen.

Wer die Pyramide umdreht und hauptsächlich MFTF-Tests schreibt, zahlt mit langen CI-Laufzeiten, hohem Wartungsaufwand und flaky Tests. Wer sie korrekt aufbaut, bekommt schnelles Feedback bei jedem Commit, zuverlässige Integrationsprüfung bei jedem Merge und E2E-Absicherung für die wichtigsten Prozesse.

Magento 2 Test-Pyramide — Das Wichtigste auf einen Blick

Unit-Tests

Basis der Pyramide. dev/tests/unit/ ohne DB. Millisekunden pro Test. Logik, Exception-Handling, Berechnungen. 70% der Tests.

Integrationstests

Mitte der Pyramide. Echte DB, voller Magento-Bootstrap. Fixtures. Datenbank-Queries, Plugin-Verhalten, Events. 25% der Tests.

MFTF

Spitze der Pyramide. Browser + volles Stack. Minuten pro Test. Kritische User-Journeys. 5% der Tests – nur für das Wesentliche.

CI-Staffelung

Unit bei jedem Commit. Integration bei jedem PR-Merge. MFTF täglich oder vor Release. Gestaffeltes Feedback, minimale Wartezeit.

Mironsoft

Magento 2 Teststrategie, PHPUnit und MFTF-Automatisierung

Teststrategie für euer Magento-Projekt aufbauen?

Wir analysieren bestehende Testlücken, bauen eine an die Projektstruktur angepasste Test-Pyramide auf und integrieren alle drei Teststufen in die CI/CD-Pipeline.

Strategie-Audit

Analyse der bestehenden Testlandschaft und Empfehlungen für die richtige Pyramide

Test-Implementierung

Unit-, Integrations- und MFTF-Tests für kritische Magento-Module aufbauen

CI-Pipeline

Gestaffelte Test-Jobs in GitHub Actions oder GitLab CI einrichten

11. FAQ: Magento 2 Test-Pyramide

1Was ist die Test-Pyramide für Magento 2?
Viele Unit-Tests an der Basis, weniger Integrationstests, wenige MFTF an der Spitze. Optimales Verhältnis: 70% Unit, 25% Integration, 5% MFTF.
2Braucht man alle drei Teststufen von Anfang an?
Nein. Mit Unit-Tests starten. Integration wenn DB-Logik getestet werden muss. MFTF erst wenn Unit und Integration etabliert sind.
3Warum sind MFTF-Tests langsamer?
Browser steuern, Seiten laden, JavaScript ausführen, DOM-Elemente warten. PHPUnit läuft in reinem PHP ohne externe Systeme – deutlich schneller.
4Was decken Integrationstests zusätzlich ab?
SQL-Korrektheit, Plugin-Verhalten, Event-Observer-Seiteneffekte, DI-Container-Konfiguration – alles, was den echten Magento-Bootstrap braucht.
5Was ist ein Fixture im Integrationstest?
PHP-Skript das Testdaten in die DB schreibt, vor dem Test ausgeführt, nach dem Test zurückgerollt. @magentoDataFixture oder #[DataFixture] verweist darauf.
6Wie verhindert man flaky MFTF-Tests?
Explicit Waits statt Sleep. Page-Object-Pattern. Test-Isolierung. Kein geteilter Zustand. Und: MFTF-Tests auf ein absolutes Minimum reduzieren.
7Drei Teststufen in GitHub Actions integrieren?
Separate Jobs mit needs-Direktive. Unit bei jedem Push, Integration bei PR-Merge, MFTF nur auf main/release. Gestaffelte Abhängigkeitskette.
8Integrationstests lokal ausführen?
Ja, mit separater Test-Datenbank. In Mark Shust Docker: bin/magento dev:tests:run integration im PHP-Container.
9Problem der umgekehrten Pyramide?
Langsame CI-Pipelines, hoher Wartungsaufwand, viele flaky Tests. Dreißig Minuten Wartezeit bei jedem Merge und Tests die aus Timing-Gründen scheitern.
10Wie messe ich ob die Pyramide gesund ist?
Anzahl und Laufzeit pro Stufe prüfen. Unit unter einer Minute, Integration unter zehn Minuten, MFTF unter dreißig Minuten. Wenn MFTF dominiert, ist die Pyramide umgekehrt.