MFTF in Magento 2: Functional Testing Framework von Grund auf
AI generated
M2
di.xml
Magento 2 · MFTF · Functional Testing · QA
MFTF: Magento Functional Testing Framework
von Grund auf aufgebaut

MFTF automatisiert genau die Klasse von Fehlern, die Unit-Tests systematisch übersehen: kaputte Checkout-Flows, fehlerhafte JavaScript-Interaktionen und Admin-Formulare, die nach einem Update plötzlich nicht mehr speichern. Wer MFTF sauber aufsetzt, bekommt einen Browser-gestützten Absicherungslayer, der echte Klickpfade im Storefront und Backend automatisch nachstellt und Regressionen findet, bevor Kunden sie finden.

17 Min. Lesezeit Test-XML · ActionGroups · Page Objects · CI Magento 2.4.8 · PHP 8.4

1. Was MFTF ist und welches Problem es löst

MFTF, das Magento Functional Testing Framework, ist Adobes offizielles Werkzeug für automatisierte End-to-End-Tests in Magento 2. Anders als PHPUnit-Tests, die einzelne Klassen isoliert prüfen, steuert MFTF einen echten Browser über Selenium WebDriver und klickt sich durch Storefront und Adminbereich wie ein echter Nutzer. Das schließt genau die Lücke, die Unit- und Integrationstests offen lassen: das Zusammenspiel aus PHP-Backend, Layout-XML, JavaScript und CSS, das erst im gerenderten Browser sichtbar wird.

In der Praxis zeigt sich der Wert von MFTF besonders nach Modul-Updates oder Theme-Änderungen. Ein Plugin, das eine Checkout-Observer-Klasse korrekt implementiert, kann trotzdem den Checkout brechen, wenn ein JavaScript-Modul nicht mehr lädt oder ein Knockout-Binding auf ein verändertes Template trifft. Genau solche Fehler deckt MFTF auf, weil es den kompletten Rendering- und Interaktionspfad im Browser durchläuft, statt nur PHP-Rückgabewerte zu prüfen.

Wichtig ist die Abgrenzung: MFTF ersetzt keine Unit-Tests und keine statische Analyse. Es ist die dritte, oberste Ebene einer Teststrategie, die typischerweise wenige, aber geschäftskritische Abläufe abdeckt, wie Produkt in den Warenkorb legen, Checkout abschließen oder ein Konfigurationsformular im Adminbereich speichern. Wer versucht, mit MFTF jede Codezeile abzudecken, baut eine Testsuite, die Stunden statt Minuten läuft und bei jeder kleinen Layout-Änderung bricht.

2. MFTF-Setup und Verzeichnisstruktur im eigenen Modul

Seit Magento 2.3 ist MFTF Teil der Standardinstallation über magento/magento2-functional-testing-framework als Composer-Abhängigkeit von magento/mtf-tests beziehungsweise direkt als Dev-Requirement. In einem eigenen Modul lebt der komplette MFTF-Testcode nicht im Modulordner selbst, sondern parallel unter dev/tests/acceptance/tests/functional/Vendor/Modul/Test/. Diese Trennung sorgt dafür, dass Testcode nicht versehentlich mit ins Produktions-Deployment wandert.

Nach dem Composer-Require folgt der Aufbau des Projekts über die MFTF-eigene CLI. Der Befehl vendor/bin/mftf build:project generiert die Konfigurationsdateien codeception.yml und .env, in denen Basis-URL, Backend-Login und Browser-Einstellungen für Selenium hinterlegt werden. Ohne eine korrekt konfigurierte .env mit gültigem MAGENTO_BASE_URL und MAGENTO_BACKEND_NAME startet keine einzige MFTF-Testklasse.


{
  "require-dev": {
    "magento/magento2-functional-testing-framework": "^4.7",
    "codeception/codeception": "^5.0"
  },
  "extra": {
    "magento-force": "override"
  }
}

Innerhalb des Moduls selbst gibt es Unterordner für jede Testartefakt-Kategorie: Test/ für die eigentlichen Testszenarien, ActionGroup/ für wiederverwendbare Schrittfolgen, Page/ und Section/ für die DOM-Struktur der Seiten sowie Data/ für Testdaten-Entities. Diese klare Trennung ist kein optionales Stilmittel, sondern zwingend für MFTF, weil das Framework die Dateien anhand ihres Ordners und ihres XML-Schemas interpretiert.

3. Anatomie eines MFTF-Tests: Test, Data, Page, Section

Ein MFTF-Test ist immer eine XML-Datei, kein PHP-Code. Das ist eine bewusste Designentscheidung von Adobe: XML-Testdefinitionen lassen sich leichter durch mehrere Extensions zusammenführen, weil Magento-Module Tests eines anderen Moduls per XML-Merge erweitern oder deaktivieren können, ohne dessen Quellcode zu verändern. Ein Test besteht aus einem eindeutigen Namen, optionalen Annotationen für Testfall-Referenzen und einer Sequenz von Schritten, die entweder direkte Aktionen oder Aufrufe von ActionGroups sind.

Jeder Schritt in einem MFTF-Test referenziert ein Element über eine Section, niemals über einen hartkodierten CSS-Selektor direkt im Test. Diese Indirektion ist zentral: ändert sich ein Selektor im Theme, wird nur die Section-Datei angepasst, nicht jeder einzelne Test, der das Element benutzt. Genau diese Struktur macht MFTF-Tests über Jahre wartbar, auch wenn sich das Frontend-Markup mehrfach ändert.


<!-- dev/tests/acceptance/tests/functional/Mironsoft/Catalog/Test/AddConfigurableProductToCartTest.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
    <test name="AddConfigurableProductToCartTest">
        <annotations>
            <features value="Catalog"/>
            <stories value="Configurable Product"/>
            <title value="Add configurable product with selected options to cart"/>
            <description value="Customer selects size and color, then adds the product to cart"/>
            <severity value="CRITICAL"/>
            <group value="catalog"/>
            <group value="configurable_product"/>
        </annotations>

        <amOnPage url="{{StorefrontProductPage.url(_defaultProduct.urlKey)}}" stepKey="goToProductPage"/>
        <waitForPageLoad stepKey="waitForProductPage"/>

        <actionGroup ref="StorefrontSelectConfigurableOptionActionGroup" stepKey="selectSize">
            <argument name="attributeCode" value="size"/>
            <argument name="optionLabel" value="M"/>
        </actionGroup>

        <click selector="{{StorefrontProductActionSection.addToCart}}" stepKey="clickAddToCart"/>
        <waitForElementVisible selector="{{StorefrontMessagesSection.success}}" stepKey="waitForSuccessMessage"/>
        <see selector="{{StorefrontMessagesSection.success}}" userInput="You added" stepKey="assertSuccessMessage"/>
    </test>
</tests>

Auffällig ist die durchgängige Nutzung von stepKey: jeder Schritt in MFTF braucht einen eindeutigen Bezeichner innerhalb des Tests. Das ermöglicht es Extensions, gezielt einen einzelnen Schritt über before oder after Attribute an einer bestimmten Stelle einzufügen, statt den gesamten Test neu schreiben zu müssen. Diese Merge-Fähigkeit ist einer der größten praktischen Vorteile gegenüber klassischem Codeception-PHP-Code.

4. Page Objects und Section Objects sauber modellieren

Page Objects definieren in MFTF eine URL samt Parametern, während Section Objects die einzelnen DOM-Elemente dieser Seite als benannte Selektoren kapseln. Diese Trennung folgt dem klassischen Page-Object-Pattern aus der Testautomatisierung und ist bei MFTF verpflichtend: kein Test darf einen rohen CSS- oder XPath-Selektor direkt enthalten, sondern muss immer über {{SectionName.elementName}} auf ein benanntes Element verweisen.

Ein häufiger Anfängerfehler ist es, für jede kleinste Seitenvariante eine eigene Page- und Section-Datei anzulegen. Sinnvoller ist es, Sections nach fachlicher Zugehörigkeit zu bündeln, etwa eine StorefrontProductActionSection für alle Kaufaktionen auf der Produktseite, unabhängig davon, ob es sich um ein einfaches oder konfigurierbares Produkt handelt. Das reduziert Duplikate und hält die MFTF-Struktur auch bei wachsender Testsuite übersichtlich.


<!-- dev/tests/acceptance/tests/functional/Mironsoft/Catalog/Page/StorefrontProductPage.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageSchema.xsd">
    <page name="StorefrontProductPage" url="/{{urlKey}}.html" module="Mironsoft_Catalog" area="storefront" parameterized="true">
        <section name="StorefrontProductActionSection"/>
    </page>
</pages>

<!-- dev/tests/acceptance/tests/functional/Mironsoft/Catalog/Section/StorefrontProductActionSection.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionSchema.xsd">
    <section name="StorefrontProductActionSection">
        <element name="addToCart" type="button" selector="#product-addtocart-button" timeout="30"/>
        <element name="qty" type="input" selector="#qty" timeout="10"/>
        <element name="swatchOption" type="text" selector=".swatch-option[option-label='{{var1}}']" parameterized="true"/>
    </section>
</sections>

Das Attribut parameterized="true" erlaubt es, Platzhalter wie {{var1}} in Selektoren zu nutzen, die beim Testaufruf mit konkreten Werten gefüllt werden. Damit lässt sich ein einziges Selector-Element für alle Swatch-Optionen eines konfigurierbaren Produkts wiederverwenden, statt für jede Farbe und Größe einen eigenen Selektor zu pflegen. Für MFTF-Projekte mit vielen Produktvarianten ist das der entscheidende Hebel gegen Wartungsaufwand.

5. ActionGroups: wiederverwendbare Testschritte bauen

ActionGroups sind das zentrale Wiederverwendungsprinzip in MFTF. Statt in jedem Test den Login-Vorgang oder die Auswahl einer Konfigurationsoption erneut auszuschreiben, kapselt eine ActionGroup diese Schrittfolge einmal mit definierten Eingabeparametern. Jeder Test, der diese Funktionalität braucht, ruft die ActionGroup lediglich per Referenz auf. Das reduziert nicht nur Duplikation, sondern erleichtert auch Wartung: ändert sich der Login-Flow, muss nur die ActionGroup angepasst werden, nicht jeder einzelne Test.

ActionGroups unterstützen zusätzlich Vererbung über extends, wodurch eine spezialisierte Variante einer Basis-ActionGroup nur die abweichenden Schritte definieren muss. Das ist besonders nützlich, wenn zwei sehr ähnliche Abläufe existieren, etwa das Hinzufügen eines einfachen Produkts versus eines konfigurierbaren Produkts zum Warenkorb, die sich nur in wenigen Zwischenschritten unterscheiden.


<!-- dev/tests/acceptance/tests/functional/Mironsoft/Catalog/ActionGroup/StorefrontSelectConfigurableOptionActionGroup.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
    <actionGroup name="StorefrontSelectConfigurableOptionActionGroup">
        <annotations>
            <description value="Selects a configurable product option by attribute code and label"/>
        </annotations>
        <arguments>
            <argument name="attributeCode" type="string"/>
            <argument name="optionLabel" type="string"/>
        </arguments>

        <waitForElementVisible selector="{{StorefrontProductActionSection.swatchOption(optionLabel)}}" stepKey="waitForSwatch"/>
        <click selector="{{StorefrontProductActionSection.swatchOption(optionLabel)}}" stepKey="clickSwatch"/>
        <waitForElementNotVisible selector="{{StorefrontProductActionSection.optionLoader}}" stepKey="waitForPriceUpdate"/>
    </actionGroup>
</actionGroups>

Ein zweiter, oft unterschätzter Vorteil von ActionGroups ist die Testbarkeit der Testinfrastruktur selbst. Wenn eine gemeinsame Login- oder Setup-ActionGroup fehlerhaft ist, schlagen sofort alle abhängigen Tests fehl, was das Problem an der Wurzel sichtbar macht, statt es in dutzenden Einzeltests zu verstecken. Gute MFTF-Projekte investieren deshalb überproportional viel Sorgfalt in die Basis-ActionGroups für Login, Navigation und Produktauswahl.

6. MFTF-Tests generieren und ausführen

MFTF-Tests werden nicht direkt aus XML ausgeführt, sondern zunächst in PHP-Codeception-Klassen kompiliert. Der Befehl vendor/bin/mftf generate:tests liest alle XML-Testdateien, führt Merges zwischen Basis- und Extension-Modulen durch und schreibt lauffähigen PHP-Code nach dev/tests/acceptance/tests/_generated/. Dieser Schritt macht Fehler in der XML-Struktur oder fehlende Referenzen bereits vor der eigentlichen Testausführung sichtbar.

Die eigentliche Ausführung erfolgt danach über Codeception, meist gekapselt im Wrapper-Befehl vendor/bin/mftf run:test . Im Mark-Shust-Docker-Setup geschieht das typischerweise im Container über bin/cli vendor/bin/mftf run:test AddConfigurableProductToCartTest, wobei Selenium entweder als eigener Container oder über eine Cloud-Testing-Plattform bereitgestellt wird.


#!/usr/bin/env bash
# Build MFTF project configuration once after composer require
bin/cli vendor/bin/mftf build:project

# Generate PHP/Codeception test classes from XML definitions
bin/cli vendor/bin/mftf generate:tests

# Run a single test by name
bin/cli vendor/bin/mftf run:test AddConfigurableProductToCartTest

# Run all tests tagged with a specific group
bin/cli vendor/bin/mftf run:group catalog

# Run the entire suite headless, useful for CI
bin/cli vendor/bin/mftf run:test --remove-generated-and-run-only

Für lokale Entwicklung lohnt sich das Flag -k beziehungsweise --keep-generated, das die generierten PHP-Dateien nicht nach jedem Lauf löscht. So lässt sich der kompilierte Codeception-Code direkt inspizieren, wenn ein MFTF-Test sich anders verhält als erwartet und die XML-Ebene allein keine Erklärung liefert.

7. Fehlgeschlagene MFTF-Tests debuggen

Ein fehlschlagender MFTF-Test liefert standardmäßig einen Screenshot des Browserzustands im Moment des Fehlers sowie einen HTML-Snapshot der Seite, beides abgelegt unter dev/tests/acceptance/tests/_output/. Das ist der erste Anlaufpunkt bei jedem Fehlschlag: ein Blick auf den Screenshot zeigt meist sofort, ob ein Cookie-Banner den Klick blockiert hat, ein Ladeindikator noch sichtbar war oder das erwartete Element schlicht nicht existiert.

Zeitprobleme sind die mit Abstand häufigste Fehlerursache in MFTF-Tests. Ein click auf ein Element, das durch eine asynchrone Preisberechnung noch nicht interaktiv ist, führt zu einem flakigen Test, der mal besteht und mal fehlschlägt. Die Lösung ist konsequenter Einsatz von waitForElementVisible, waitForElementNotVisible und waitForPageLoad anstelle fester wait-Sekundenangaben, die entweder zu kurz oder unnötig lang sind.

Für tieferes Debugging unterstützt MFTF den Modus MFTF_DEBUG=1 in der .env-Datei, der jeden Schritt einzeln protokolliert und die Ausführung verlangsamt. Kombiniert mit einer sichtbaren Chrome-Instanz statt Headless-Modus lässt sich so live nachvollziehen, an welcher Stelle genau die erwartete Interaktion vom tatsächlichen Seitenverhalten abweicht.

8. MFTF in der CI-Pipeline betreiben

MFTF-Tests in eine CI-Pipeline zu integrieren bringt einen anderen Anspruch mit als das lokale Ausführen einzelner Tests. Ein vollständiger MFTF-Lauf braucht eine lauffähige Magento-Instanz mit Testdaten, einen Selenium-Container oder eine Remote-WebDriver-Verbindung und ausreichend Timeout-Reserven, da Browser-Interaktionen naturgemäß langsamer sind als PHP-Unit-Tests. Ohne bewusste Isolierung der Testdatenbank kollidieren parallele Pipeline-Läufe schnell mit sich selbst.

Bewährt hat sich, MFTF nicht bei jedem Commit, sondern gezielt vor Merges in den Hauptbranch oder nächtlich als vollständigen Regressionslauf auszuführen. Kritische, geschäftsrelevante Flows wie Checkout und Produktkonfiguration laufen dabei bei jedem Merge-Request, während der komplette Testkatalog nächtlich läuft. Das hält die Feedback-Zeit für Entwickler kurz und sichert trotzdem regelmäßig die volle Breite ab.

Ein oft übersehener Punkt ist die Stabilität der Testumgebung selbst. Wechselnde Produktdaten, ablaufende Rabattaktionen oder sich ändernde Preise in der CI-Datenbank führen zu Tests, die ohne Codeänderung plötzlich fehlschlagen. Deshalb sollte jede MFTF-Pipeline mit einem reproduzierbaren Datenbank-Fixture starten, das vor jedem Lauf frisch eingespielt wird, statt auf einen sich ständig ändernden Staging-Datenbestand zu vertrauen.

9. MFTF im Vergleich zu Unit- und Integrationstests

Die Entscheidung, welche Testebene ein bestimmtes Verhalten absichern sollte, ist keine Geschmacksfrage, sondern hat direkte Auswirkungen auf Laufzeit, Wartungsaufwand und Aussagekraft. MFTF ist die richtige Wahl für Abläufe, die mehrere Systemschichten und den Browser einbeziehen, aber die falsche Wahl für die Prüfung einzelner Geschäftsregeln.

Testebene Werkzeug Prüft Laufzeit pro Test
Unit-Tests PHPUnit Isolierte Klassenlogik, Geschäftsregeln Millisekunden
Integrationstests PHPUnit + Magento-Testframework Zusammenspiel von DI, DB und Modulen Sekunden
MFTF MFTF + Codeception + Selenium Kompletter Klickpfad im echten Browser Zehn Sekunden bis Minuten
Manuelle QA Mensch Exploratives Testen, visuelle Feinheiten Minuten bis Stunden

Die praktische Faustregel: Geschäftslogik gehört in Unit-Tests, das Zusammenspiel mehrerer Magento-Komponenten in Integrationstests, und nur die wirklich kritischen End-to-End-Pfade, bei denen der Browser selbst Teil des Risikos ist, gehören in MFTF. Eine Testpyramide mit vielen Unit-Tests, weniger Integrationstests und wenigen, aber gezielten MFTF-Tests bleibt schnell, stabil und aussagekräftig zugleich.

Mironsoft

MFTF-Testautomatisierung, CI-Integration und Magento-2-Qualitätssicherung

Checkout und Konfigurator automatisch absichern?

Wir bauen MFTF-Testsuiten für eure geschäftskritischen Magento-2-Abläufe auf, von der Verzeichnisstruktur über ActionGroups bis zur stabilen CI-Pipeline mit reproduzierbaren Testdaten.

MFTF-Setup

Projektstruktur, Page Objects und Basis-ActionGroups sauber aufsetzen

Testabdeckung

Checkout, Konfigurator und Adminformulare gezielt automatisieren

CI-Integration

Stabile, reproduzierbare MFTF-Läufe in eure Pipeline integrieren

10. Zusammenfassung

MFTF schließt in Magento 2 eine Lücke, die keine andere Testebene abdecken kann: das Verhalten des kompletten Systems im echten Browser, inklusive JavaScript, CSS und Rendering. Die klare Trennung in Test, Page, Section, ActionGroup und Data macht Testsuiten wartbar, auch wenn sich Frontend-Markup über Jahre hinweg mehrfach ändert. Wer Selektoren konsequent in Section-Dateien kapselt und wiederkehrende Abläufe in ActionGroups auslagert, baut eine MFTF-Suite, die mit dem Projekt mitwächst statt bei jedem Release neu geschrieben zu werden.

Der entscheidende Erfolgsfaktor ist Disziplin bei der Auswahl der abzudeckenden Szenarien. MFTF eignet sich für wenige, aber geschäftskritische End-to-End-Pfade, nicht für die vollständige Abdeckung jeder Codezeile. Kombiniert mit einer stabilen CI-Pipeline, reproduzierbaren Testdaten und konsequenten Wait-Strategien wird MFTF zu einem verlässlichen Absicherungsnetz, das echte Regressionen findet, bevor sie im Live-Shop sichtbar werden.

MFTF in Magento 2: Das Wichtigste auf einen Blick

Was MFTF ist

Adobes Framework für Browser-gestützte End-to-End-Tests, oberhalb von Unit- und Integrationstests angesiedelt.

Struktur

Test, ActionGroup, Page, Section und Data als eigene XML-Dateien mit klarer Zuständigkeit.

Stabilität

Explizite Waits statt fester Sekundenangaben sind die wichtigste Maßnahme gegen flakige MFTF-Tests.

CI-Betrieb

Reproduzierbare Testdaten und gezielte Testauswahl statt vollständigem Lauf bei jedem Commit.

11. FAQ: MFTF in Magento 2

1Was ist MFTF in Magento 2?
Adobes Framework für Browser-gestützte End-to-End-Tests über Selenium WebDriver, das komplette Nutzerabläufe im Storefront und Adminbereich nachstellt.
2Wie unterscheidet sich MFTF von PHPUnit?
PHPUnit prüft isolierte Logik in PHP, MFTF prüft den kompletten Ablauf im echten Browser inklusive Rendering und JavaScript.
3Wo liegen MFTF-Tests im Modul?
Unter dev/tests/acceptance/tests/functional/Vendor/Modul, getrennt vom eigentlichen Produktionscode.
4Warum keine direkten CSS-Selektoren im Test?
Selektoren liegen in Section-Dateien. Ändert sich das Theme, wird nur die Section angepasst, nicht jeder Test.
5Was ist eine ActionGroup?
Eine wiederverwendbare Schrittfolge mit Argumenten, etwa Login oder Produktauswahl, die mehrere Tests per Referenz nutzen.
6Wie führe ich einen einzelnen Test aus?
Mit vendor/bin/mftf run:test TestName, nach vorherigem generate:tests, im Docker-Setup über bin/cli.
7Warum ist mein Test flaky?
Meist fehlende explizite Waits. waitForElementVisible statt fester Sekundenangaben löst die meisten Fälle.
8Sollte MFTF bei jedem Commit laufen?
In der Regel nicht vollständig. Kritische Flows bei jedem Merge-Request, der volle Katalog eher nächtlich.
9Kann MFTF Unit-Tests ersetzen?
Nein. MFTF deckt wenige kritische End-to-End-Pfade ab, Geschäftsregeln bleiben Aufgabe schneller Unit-Tests.
10Wie debuggt man einen fehlgeschlagenen Test?
Über Screenshot und HTML-Snapshot im _output-Verzeichnis, ergänzt um MFTF_DEBUG=1 und sichtbaren statt headless Browser.