Création de tests d'intégration pour les modules Magento 2

27

Jusqu'à présent, pour mes besoins de test Magento 2, j'ai utilisé PHP Unit comme (plus ou moins) testeur d'acceptation - testant les résultats des requêtes serveur et HTML faites dans un système avec mon ou mes modules installés. J'aimerais pouvoir créer mes propres tests d'intégration. Les outils de test fournis avec Magento 2 permettent-ils aux développeurs tiers de créer leurs propres tests d'intégration qui exploitent le code du framework de test de Magento? Ou allons-nous tous lancer notre propre bootstrap?

C'est

  1. Je suis développeur Magento
  2. J'aimerais créer un test d'intégration
  3. Je ferais mon test d'intégration pour avoir un environnement Magento entièrement bootstrap dans lequel jouer (ie gestionnaire d'objets et / ou injection de dépendance à utiliser)
  4. J'aimerais que mon test d'intégration prolonge le Magento\TestFramework\TestCase\AbstractControllertest, donc j'ai les mêmes aides que les tests Magento
  5. Je voudrais pouvoir exécuter mes tests indépendamment du reste de la suite de tests (c'est-à-dire ne pas avoir à attendre 2 heures pour exécuter mes 15 secondes de tests)
  6. J'aimerais que mes tests soient stockés séparément des tests de Magento

Le site dev docs contient des articles de démarrage sur les tests, mais ils semblent orientés vers l'exécution des tests fournis avec Magento et non vers la création et l'exécution de vos propres tests. Il y a les anciens exemples de modules , mais ils étendent tous la PHPUnit_Framework_TestCaseclasse et semblent être des tests unitaires (c'est-à-dire tester du code qui ne repose pas sur le framework Magento)

Existe-t-il un moyen fourni par Magento?

Sinon, quelqu'un a-t-il déployé sa propre configuration de manière à ce que le test de la communauté des développeurs Magento puisse l'adopter comme standard?

Alan Storm
la source

Réponses:

20

Cela fonctionne pour nous, mais nous n'avons pas encore envisagé de les déplacer vers un emplacement distinct pour l'adresse 6.)

1.) Placez vos tests d'intégration sous dev/tests/integration/testsuite/Vendor
2.) copiez dev/tests/integration/phpunit.dist.xml
dans
dev/tests/integration/phpunit.xml

et remplacer

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

avec

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

3.) exécutez-le ../../../vendor/bin/phpunitou avec à ../../../vendor/bin/phpunit path/to/testspartir du dossier dev / test / integration

Veuillez noter que les tests d'intégration prennent plus de 15 secondes, au moins à la première exécution car il installe essentiellement Magento. Vous pouvez économiser sur les exécutions suivantes si vous utilisez

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

dans votre phpunit.xml

Kristof chez Fooman
la source
11

Je l' ai placé avec succès mes tests d'intégration dans un répertoire distinct: src/My/Module/test/integration. Il pourrait également s'agir de n'importe quel autre répertoire app/code/My/Module/Test.

Les ajouter comme nouvelle suite de test pour les tests d'intégration Magento: Copier dev/tests/integration/phpunit.xml.distpour dev/tests/integration/phpunit.xmlet ajouter ce qui suit dans le <testsuites>noeud:

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

Exécutez ensuite les tests comme celui-ci à partir du dev/tests/integrationrépertoire:

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

Avec le --testsuiteparamètre, vous pouvez sélectionner une suite de tests par nom, afin que tous les tests d'intégration ne soient pas exécutés en même temps

Mise à jour: Calendrier

Pour utiliser ses propres appareils, une petite solution de contournement était nécessaire, car dans Magento\TestFramework\Annotationle répertoire de base des appareils, il est défini globalement. Mais heureusement, Magento autorise également les noms de méthode en tant qu'appareils, ce qui fonctionne:

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

public static function loadFixture()
{
    include __DIR__ . '_files/something_fixture.php';
}
Fabian Schmengler
la source
1
Ne rencontreriez-vous pas des problèmes lors de l'utilisation de @magentoDataFixture ici github.com/magento/magento2/blob/develop/dev/tests/integration/… en particulier lors de la combinaison avec un luminaire personnalisé de votre module avec un core?
Kristof au Fooman
1
tbh je ne l'ai pas encore essayé mais ça ressemble à un problème, ouais. Il peut être nécessaire de définir le chemin d'inclusion pour que ces appareils fonctionnent.
Fabian Schmengler
1
@KristofatFooman Trouvé une solution pour les luminaires, voir la mise à jour
Fabian Schmengler
Excellente solution. Il pourrait y avoir quelques défauts ici. Tout d'abord, il y a une faute de frappe - la __DIR__devrait être suivie d'une barre oblique ( /_files). Deuxièmement, le luminaire est chargé à partir de TestFramework de sorte que le __DIR__pointe vers le répertoire TestFramework et non vers votre propre module. Le ComponentRegistrarpeut être utilisé pour cela:require $ObjectManager::getInstance()->get(ComponentRegistrar::class)->getPath('module', 'Foo_Bar').'/Test/Integration/_files/example.php';
Jisse Reitsma
10

J'ai un peu joué avec les tests d'intégration, et c'est ce que j'ai trouvé jusqu'à présent.

Fondamentalement, j'ai suivi des étapes similaires à celles de Fooman, avec quelques différences afin que le test d'intégration fasse partie de mon module.

Voici les étapes que j'ai suivies:

1- Placez vos tests d'intégration sous app/code/Vendor/CustomModule/Test/Integration

2- Copier dev/tests/integration/phpunit.dist.xmlversdev/tests/integration/phpunit.xml

et remplacer

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

avec

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

3- Ensuite je l'exécute à l'aide de l'outil CLI bin/magento dev:test:run integration

Vous devez avoir à l'esprit ce que Fooman dit sur le "TESTS_CLEANUP" et le temps qu'il faut pour configurer les tests d'intégration si vous avez activé le nettoyage.

Ici, j'ajoute un exemple fonctionnel pour référence ultérieure. Vous verrez comment vous pouvez accéder au gestionnaire d'objets et générer une instance de classes Magento, ainsi que l'utilisation des appareils Magento.

application / code / fournisseur / module personnalisé / contrôleur / commande / 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>

application / code / fournisseur / module personnalisé / test / intégration / contrôleur / commande / 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
la source
Veuillez noter que votre propre solution est très bien et qu'elle fonctionne, tant que vous utilisez les appareils du noyau Magento. Si vous souhaitez utiliser vos propres appareils, vous rencontrerez les problèmes décrits ci-dessus.
Jisse Reitsma