Best Practice für Unit-Tests in Magento 1.9

11

Ich unterhalte eine Magento 1.9-Site mit mehreren benutzerdefinierten Modulen. Einige der Funktionen sind geschäftskritisch und erfordern dringend einige Komponententests. ZB ein Stückpreisrechner.

Normalerweise entwickle ich in Symfony und würde es wirklich vorziehen, PHPUnit (mit Composer) zu verwenden, wenn das überhaupt möglich ist.

Einige Funktionen basieren auf Daten, die in mehrere benutzerdefinierte Datenbanktabellen importiert wurden. Daher würde ich es vorziehen, Fixtures irgendwie zu laden.

Daher suche ich nach dem Best-Practice-Ansatz für das Schreiben einiger Komponententests. Gerne nehme ich Tutorials oder ähnliches an. Jede Hilfe wird geschätzt.

frigg
quelle

Antworten:

10

Ich hatte vor einiger Zeit das gleiche Problem.

Ich habe überlegt, das Ecomdev PHPUnit-Modul zu verwenden , finde es jedoch schwierig zu verwenden und schlecht dokumentiert (aber ich liebe immer noch, was Ivan tut und seinen großen Beitrag zum Magento-Ökosystem).

Mit Hilfe von Vinai habe ich das folgende Test-Framework-Modul entwickelt: https://github.com/digitalpianism/testframework

Der ursprüngliche Zweck war für Integrationstests, aber ich verwende es auch für Unit-Tests. Sie können es hier in Aktion sehen: https://github.com/digitalpianism/easytoplinks/blob/master/app/code/community/DigitalPianism/EasyToplinks/Test/Unit/Block/Page/Template/LinksTest.php

In Bezug auf Fixtures verwende ich Transaktions-Rollbacks, um zu vermeiden, dass Beispieldaten in der Datenbank erstellt werden.

Raphael beim digitalen Pianismus
quelle
Das sieht wirklich vielversprechend aus. Ich werde es ausprobieren. Vielen Dank.
Frigg
13

Installation

Da Magento 1 Composer nicht sofort verwendet, macht es meiner Meinung nach keinen großen Unterschied, ob Sie phpunit mit Composer installieren oder einfach die Phar- Version herunterladen .
Wenn Sie Composer bereits zum Verwalten anderer Module oder Bibliotheken von Drittanbietern auf Ihrer Site verwenden, ist Composer wahrscheinlich am sinnvollsten. Wenn Sie PHP7 nicht verwenden, sind Sie jedoch auf eine alte Version von phpunit beschränkt (deshalb habe ich auf die obige Version 4.8 verlinkt).

Integrationstests gegen / und / oder Unit-Tests

Da Magento 1 eine so schwere Anwendung ist, ist es sinnvoll, den phpunit-Bootstrap für die Integration in einen für die Integration und einen für Unit-Tests zu unterteilen.
Der Unit-Test-Bootstrap muss nur den Autoloader initialisieren, während der Integrationstest-Bootstrap die gesamte Anwendungsumgebung einschließlich des Konfigurationsladens und der Datenbankverbindung initialisieren muss.
Aus diesem Grund werden Integrationstests in Magento in der Regel viel langsamer ausgeführt als Unit-Tests (noch mehr als in anderen Anwendungen).

Bootstrapping von Magento in phpunit

  • Der Autoloader von Magento ist nicht PSR-0-kompatibel, da er eine Ausnahme class_existsauslöst, wenn er die Datei, in der sich eine Klasse befindet, nicht finden kann. Dadurch werden einige Verwendungen von in phpunit unterbrochen. Es gibt mehrere mögliche (wenn auch hackige) Problemumgehungen:

    • Heben Sie die \Varien_Autoload::autoload()Registrierung des Magento-Autoloaders auf, indem Sie einen Dekorator einschließen, der die darin enthaltenen Ausnahmen ignoriert, und registrieren Sie den Wrapper als neuen Autoloader. Dies hat eine geringe Wahrscheinlichkeit von Konflikten mit Bibliotheken von Drittanbietern, die Autoloader registrieren und von einer bestimmten Autoloader-Reihenfolge abhängen.
    • Verwenden Sie einen benutzerdefinierten Fehlerhandler, der den in Magento 1 integrierten umschließt. Der benutzerdefinierte Fehlerhandler verschluckt vom Magento-Autoloader ausgelöste Fehler. Dies ist die Lösung, die Raphaels Testframework verwendet . Dies scheint am besten mit anderen Erweiterungen von Drittanbietern kompatibel zu sein.
    • Verwenden Sie den Include-Path-Hack zum Überschreiben, \Varien_Autoload::autoload()um den Fehler nicht auszulösen, wenn die Datei nicht vorhanden ist. Dies steht jedoch im Widerspruch zu mehreren Modulen, die dieselbe Klasse ebenfalls überschreiben. Ich benutze diesen Ansatz nicht selbst.
  • Um zu vermeiden, dass während des Tests Fehler beim Starten der Sitzung auftreten, legen Sie diese einfach $_SESSON = []im Bootstrap fest.

  • Legen Sie ein benutzerdefiniertes Antwortobjekt fest, über Mage::app()->setResponse($testResponse)das das reale erweitert wird, das jedoch keine Ausgabe oder Header sendet.

  • Verwenden Sie, um Magento zwischen Integrationstests neu zu initialisieren, die den Laufzeitstatus vollständig ändern Mage::reset(); Mage::app(). Beachten Sie, dass der Fehlerbehandler danach neu dekoriert werden muss.

Vorrichtungen

Für DB-Fixtures verwende ich normalerweise die regulären Modelle in Fixture-Methoden, um Fixtures zu erstellen, z createSimpleProduct($sku). Verwenden Sie setUp()und wie Raphael sagte, um tearDown()den Test in eine Transaktion zu verpacken, die nach dem Test (zum Beispiel Mage::getSingleton('core/resource')->getConnection('default_setup')->beginTransaction()) zurückgesetzt wird.

Bei Fixtures mit Speicherkonfiguration tendiere ich dazu, nur In-Memory-Fixtures mit einzurichten Mage::app()->getStore()->setConfig($path, $value).

Die EcomDev_PHPUnitErweiterung bietet auch die Möglichkeit, DB-Fixtures mit Yaml-Dateien zu erstellen, aber für mich ist es schwieriger, diese zu pflegen, als mit Fixtures, die mit Modellklassen erstellt wurden. YMMV.

Test Doppel

Die Registrierung kann verwendet werden , um Test Doppel für Objekte über erstellt zu injizieren Mage::getSingleton(), Mage::getResourceSingleton()und Mage::helper().
Einige andere zentrale Objekte können aktiviert werden Mage::app()(z. B. die Anforderung).
Um Klassen zu ersetzen, die über Mage::getModel()oder Mage::getResourceModel()durch Test-Doubles erstellt wurden, muss ein benutzerdefinierter Konfigurationsobjekt-Wrapper verwendet werden. Sehen Sie sich dieses Beispiel in Raphaels Testframework an, wie dies erreicht werden kann.

Zusammenfassung

Sobald Magento gebootet ist, kann so ziemlich alles ziemlich gut getestet werden. Seien Sie jedoch darauf vorbereitet, tiefe Verspottungen zu erstellen, da der Kerncode eine große Anzahl von Methoden verkettet.
Obwohl das Setup hackig ist, funktioniert es gut und ich finde, dass die Tests mir viel Selbstvertrauen und Wert geben, ziemlich vergleichbar mit einer Testsuite für eine Symphony-App.

Vinai
quelle
Ich habe es nie ausprobiert, aber warum nicht Magento Test Framework verwenden? ( docs.magento.com/m1/ce/user_guide/magento/… )
Fra
3
Ja, ich habe es versucht, aber es ist ein Funktionstest (keine Einheit oder Integration), es ist langsam, es ist komplex und die Tests sind in der Regel schuppig und spröde. Alles in allem hielt ich die Zeit, die ich damit verbrachte, für eine Verschwendung.
Vinai
@Vinai Ich weiß, dass es spät ist, aber im Allgemeinen gibt es in einem Controller Aufrufe zu Modellen und Sammlungen, die wir beim Testen nicht benötigen. Ich verwende Ihr Test-Framework (DigitalPianism) und dort können wir die Modelle testen. Wenn ich jedoch eine Get-Anfrage an eine Controller-Aktion stelle, die wiederum ein Modell verwendet, wie kann ich diesen Modell- / Sammlungsaufruf verspotten?
Arqam