Erstellen von Integrationstests für Magento 2-Module

27

Bisher habe ich für meine Magento 2-Testanforderungen PHP Unit als (mehr oder weniger) Abnahmetester verwendet. Dabei wurden die Ergebnisse von Server- und HTML-Anforderungen getestet, die auf einem System mit installierten Modulen ausgeführt wurden. Ich möchte meine eigenen Integrationstests erstellen können. Ermöglichen die mit Magento 2 gelieferten Testtools Entwicklern von Drittanbietern, ihre eigenen Integrationstests zu erstellen, die den Test-Framework-Code von Magento nutzen? Oder werden wir alle unseren eigenen Bootstrap rollen?

Das ist

  1. Ich bin ein Magento-Entwickler
  2. Ich möchte einen Integrationstest erstellen
  3. Ich würde meinen Integrationstest durchführen, um eine vollständig bootfähige Magento-Umgebung zum Spielen zu haben (dh Objektmanager und / oder Abhängigkeitsinjektion zur Verwendung).
  4. Ich möchte, dass mein Integrationstest den Test erweitert Magento\TestFramework\TestCase\AbstractController, damit ich die gleichen Helfer wie Magento-Tests habe
  5. Ich möchte in der Lage sein, meine Tests isoliert vom Rest der Testsuite auszuführen (dh ich muss nicht 2 Stunden warten, um meine 15 Sekunden langen Tests auszuführen)
  6. Ich möchte, dass meine Tests getrennt von Magentos Tests gespeichert werden

Die dev docs-Site enthält einige Einstiegsartikel zum Testen, aber sie scheinen darauf ausgerichtet zu sein, die mit Magento gelieferten Tests auszuführen und keine eigenen Tests zu erstellen und auszuführen. Es gibt die alten Beispielmodule , aber alle erweitern die PHPUnit_Framework_TestCaseKlasse und scheinen Unit-Tests zu sein (dh Code zu testen, der nicht auf dem Magento-Framework basiert).

Gibt es eine von Magento bereitgestellte Möglichkeit, dies zu tun?

Wenn nicht, hat jemand sein eigenes Setup so gerollt, dass der Test der Magento-Entwicklergemeinde es als Standard übernehmen könnte?

Alan Storm
quelle

Antworten:

20

Dies funktioniert für uns, aber wir haben noch nicht darüber nachgedacht, sie an einen anderen Ort zu verlegen, um Adresse 6 zu erhalten.)

1.) Platzieren Sie Ihre Integrationstests unter dev/tests/integration/testsuite/Vendor
2.) Kopieren dev/tests/integration/phpunit.dist.xml
nach
dev/tests/integration/phpunit.xml

und ersetzen

        <directory suffix="Test.php">testsuite</directory>
        <directory suffix="Test.php">../../../update/dev/tests/integration/testsuite</directory>
        <exclude>testsuite/Magento/Test/Integrity</exclude>
        <exclude>testsuite/Magento/MemoryUsageTest.php</exclude>

mit

        <directory suffix="Test.php">testsuite/Vendor</directory>

3.) starte es ../../../vendor/bin/phpunitoder mit ../../../vendor/bin/phpunit path/to/testsdem dev / test / integration Ordner

Bitte beachten Sie, dass die Integrationstests, zumindest beim ersten Start, länger als 15 Sekunden dauern, da Magento im Wesentlichen installiert wird. Sie können bei späteren Durchläufen sparen, wenn Sie verwenden

<const name="TESTS_CLEANUP" value="disabled"/>

in deinem phpunit.xml

Kristof bei Fooman
quelle
11

Ich habe erfolgreich meine Integrationstests in einem separaten Verzeichnis abgelegt sind : src/My/Module/test/integration. Es kann sich auch um ein anderes Verzeichnis handeln app/code/My/Module/Test.

Fügen Sie sie als neue Testsuite zu den Magento-Integrationstests hinzu: Kopieren Sie dev/tests/integration/phpunit.xml.distsie dev/tests/integration/phpunit.xmlin den <testsuites>Knoten und fügen Sie Folgendes hinzu :

<testsuite name="My_Module">
    <directory suffix="Test.php">../../../src/My/Module/test</directory>
</testsuite>

Führen Sie dann die folgenden Tests aus dem dev/tests/integrationVerzeichnis aus:

../../../vendor/bin/phpunit --testsuite "My_Module"

Mit dem --testsuiteParameter können Sie eine Testsuite nach Namen auswählen, so dass nicht alle Integrationstests gleichzeitig ausgeführt werden

Update: Spielpaarungen

Um eigene Fixtures zu verwenden, war eine kleine Umgehung nötig, da im Magento\TestFramework\AnnotationFixture Base Directory global definiert ist. Glücklicherweise erlaubt Magento aber auch Methodennamen als Fixtures, so dass folgendes funktioniert:

/**
 * @magentoDataFixture loadFixture
 */
public function testSomething()
{
}

public static function loadFixture()
{
    include __DIR__ . '_files/something_fixture.php';
}
Fabian Schmengler
quelle
1
Würden Sie nicht auf Probleme stoßen , wenn die @magentoDataFixture hier mit github.com/magento/magento2/blob/develop/dev/tests/integration/... besonders wenn sie mit einer benutzerdefinierten Befestigung von Ihrem Modul mit einem Kern einer Kombination?
Kristof bei Fooman
1
tbh Ich habe es noch nicht ausprobiert, aber es sieht nach einem Problem aus, ja. Möglicherweise müssen Sie den Include-Pfad festlegen, damit diese Fixtures funktionieren.
Fabian Schmengler
1
@KristofatFooman Eine Lösung für die Spielpaarungen gefunden, siehe Update
Fabian Schmengler
Großartige Lösung. Möglicherweise gibt es hier ein paar Mängel. Zuallererst gibt es einen Tippfehler - dem __DIR__sollte ein Schrägstrich ( /_files) folgen . Zweitens wird das Gerät aus dem TestFramework geladen, so dass es __DIR__auf das TestFramework-Verzeichnis und nicht auf Ihr eigenes Modul verweist. Die ComponentRegistrarkönnen dafür verwendet werden:require $ObjectManager::getInstance()->get(ComponentRegistrar::class)->getPath('module', 'Foo_Bar').'/Test/Integration/_files/example.php';
Jisse Reitsma
10

Ich habe ein bisschen mit den Integrationstests gespielt, und das habe ich bisher gefunden.

Grundsätzlich habe ich ähnliche Schritte wie Fooman ausgeführt, mit einigen Unterschieden, damit der Integrationstest Teil meines Moduls wird.

Dies sind die Schritte, denen ich gefolgt bin:

1- Platzieren Sie Ihre Integrationstests unter app/code/Vendor/CustomModule/Test/Integration

2- Kopieren dev/tests/integration/phpunit.dist.xmlnachdev/tests/integration/phpunit.xml

und ersetzen

<testsuite name="Magento Integration Tests">
    <directory suffix="Test.php">testsuite</directory>
    <directory suffix="Test.php">../../../update/dev/tests/integration/testsuite</directory>
    <exclude>testsuite/Magento/Test/Integrity</exclude>
    <exclude>testsuite/Magento/MemoryUsageTest.php</exclude>
</testsuite>

mit

<testsuite name="Magento Integration Tests">
    <directory suffix="Test.php">../../../app/code/Vendor/CustomModule/Test/Integration</directory>
</testsuite>

3- Dann starte ich es mit dem CLI-Tool bin/magento dev:test:run integration

Sie sollten berücksichtigen, was Fooman über "TESTS_CLEANUP" sagt und wie lange es dauert, die Integrationstests einzurichten, wenn Sie die Bereinigung aktiviert haben.

Hier füge ich ein Funktionsbeispiel als weitere Referenz hinzu. Sie werden sehen, wie Sie auf den Objektmanager zugreifen und eine Instanz von Magento-Klassen generieren sowie Magento-Fixtures verwenden können.

app / code / Vendor / CustomModule / Controller / Bestellung / Info.php

namespace Vendor\CustomModule\Controller\Order;

use Magento\Framework\Controller\ResultFactory;

class Info
    extends \Magento\Framework\App\Action\Action
{
    /**
     * @param \Magento\Framework\App\Action\Context $context
     * @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository
     */
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Sales\Api\OrderRepositoryInterface $orderRepository
    )
    {
        $this->orderRepository = $orderRepository;
        parent::__construct($context);
    }

    /**
     * Return Json OrderInfo
     *
     * @return \Magento\Framework\Controller\Result\Json $this
     */
    public function execute()
    {
        $orderId = $this->getRequest()->getParam('id');
        $order = $this->orderRepository->get($orderId);
        $orderInfo = [
            'total' => $order->getBaseGrandTotal()
        ];

        /** @var \Magento\Framework\Controller\Result\Json $result */
        $result = $this->resultFactory->create(ResultFactory::TYPE_JSON);
        return $result->setData($orderInfo);
    }

}

app / code / Vendor / CustomModule / etc / frontend / routes.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
    <router id="standard">
        <route id="vendor_custommodule" frontName="vendor_custommodule">
            <module name="Vendor_CustomModule"/>
        </route>
    </router>
</config>

app / code / Vendor / CustomModule / etc / module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Vendor_CustomModule" setup_version="1.0.0">
        <sequence>
            <module name="Magento_Sales" />
        </sequence>
    </module>
</config>

app / code / Vendor / CustomModule / Test / Integration / Controller / Bestellung / InfoTest.php

namespace Vendor\CustomModule\Controller\Order;

use Magento\TestFramework\TestCase\AbstractController;

class InfoTest extends AbstractController
{
    public function getOrderInfoActionDataProvider()
    {
        return [
            'order with one simple item' => [
                'incrementId' => '100000001',
                'contentType' => 'application/json',
                'orderTotal' => 100
            ]
        ];
    }

    /**
     * @dataProvider getOrderInfoActionDataProvider
     * @magentoDataFixture Magento/Sales/_files/order.php
     */
    public function testOrderInfoAction($incrementId, $expectedContentType, $expectedOrderTotal)
    {
        /** @var $objectManager \Magento\TestFramework\ObjectManager */
        $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();

        /** @var \Magento\Sales\Model\OrderFactory $orderFactory */
        $orderFactory = $objectManager->get('Magento\Sales\Model\OrderFactory');
        $order = $orderFactory->create();
        $order->loadByIncrementId($incrementId);

        $this->dispatch("vendor_custommodule/order/info/id/{$order->getId()}");

        $contentType = $this->getResponse()->getHeader('Content-Type');
        $this->assertEquals($expectedContentType, $contentType->getFieldValue());

        $responseJson = $this->getResponse()->getBody();
        $responseArray = json_decode($responseJson, true);
        $this->assertEquals($expectedOrderTotal, $responseArray['total']);
    }
}

app / code / Vendor / CustomModule / registration.php

\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Vendor_CustomModule',
    __DIR__
);
Facundo Capua
quelle
Bitte beachten Sie, dass Ihre eigene Lösung in Ordnung ist und funktioniert, solange Sie die Fixtures des Magento-Kerns verwenden. Wenn Sie Ihre eigenen Geräte verwenden möchten, werden Sie auf die oben beschriebenen Probleme stoßen.
Jisse Reitsma