Creación de pruebas de integración para módulos Magento 2

27

Hasta ahora para mis necesidades de prueba de Magento 2, he estado usando la Unidad PHP como (más o menos) un probador de aceptación, probando los resultados de las solicitudes de servidor y HTML realizadas en un sistema con mi (s) módulo (s) instalado (s). Me gustaría poder crear mis propias pruebas de integración. ¿Las herramientas de prueba que se incluyen con Magento 2 permiten a los desarrolladores externos crear sus propias pruebas de integración que aprovechan el código del marco de prueba de Magento? ¿O todos estaremos rodando nuestro propio arranque?

Es decir

  1. Soy un desarrollador de Magento
  2. Me gustaría crear una prueba de integración.
  3. Me gustaría que mi prueba de integración tuviera un entorno Magento de arranque completo para jugar (es decir, administrador de objetos y / o inyección de dependencia para usar)
  4. Me gustaría que mi prueba de integración extienda la Magento\TestFramework\TestCase\AbstractControllerprueba para tener los mismos ayudantes que las pruebas de Magento
  5. Me gustaría poder ejecutar mis pruebas de forma aislada del resto del conjunto de pruebas (es decir, no tener que esperar 2 horas para ejecutar mis 15 segundos de pruebas)
  6. Me gustaría que mis pruebas se almacenen por separado de las pruebas de Magento

El sitio de documentos de desarrollo tiene algunos artículos iniciales sobre pruebas, pero parecen orientados a ejecutar las pruebas que se envían con Magento y no a crear y ejecutar sus propias pruebas. Están los módulos de muestra antiguos , pero todos extienden la PHPUnit_Framework_TestCaseclase y parecen ser pruebas unitarias (es decir, código de prueba que no se basa en el marco de Magento)

¿Hay alguna forma proporcionada por Magento de hacer esto?

Si no, ¿alguien ha implementado su propia configuración de tal manera que la prueba de la comunidad de desarrolladores de Magento pueda adoptarla como estándar?

Alan Storm
fuente

Respuestas:

20

Esto funciona para nosotros, pero aún no hemos considerado moverlos a una ubicación separada para abordar la dirección 6.)

1.) Coloque sus pruebas de integración en dev/tests/integration/testsuite/Vendor
2.) copie dev/tests/integration/phpunit.dist.xml
a
dev/tests/integration/phpunit.xml

y reemplazar

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

con

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

3.) ejecútelo ../../../vendor/bin/phpunito ../../../vendor/bin/phpunit path/to/testsdesde la carpeta dev / test / integración

Tenga en cuenta que las pruebas de integración demoran más de 15 segundos, al menos en la primera ejecución, ya que esencialmente instala Magento. Puede guardar en ejecuciones posteriores si usa

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

en tus phpunit.xml

Kristof en Fooman
fuente
11

Ya he realizado con éxito mis pruebas de integración en un directorio independiente: src/My/Module/test/integration. También podría ser cualquier otro directorio, como app/code/My/Module/Test.

Agregarlos como nuevo banco de pruebas para las pruebas de integración de Magento: Copiar dev/tests/integration/phpunit.xml.dista dev/tests/integration/phpunit.xmly añadir lo siguiente en el <testsuites>nodo:

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

Luego ejecute las pruebas como esta desde el dev/tests/integrationdirectorio:

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

Con el --testsuiteparámetro puede seleccionar un conjunto de pruebas por nombre, de modo que no todas las pruebas de integración se ejecuten a la vez

Actualización: accesorios

Para usar dispositivos propios, era necesaria una pequeña solución, porque en Magento\TestFramework\Annotationel directorio base del dispositivo se define globalmente. Pero afortunadamente, Magento también permite nombres de métodos como accesorios, por lo que funciona lo siguiente:

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

public static function loadFixture()
{
    include __DIR__ . '_files/something_fixture.php';
}
Fabian Schmengler
fuente
1
¿No tendrías problemas al usar el @magentoDataFixture aquí github.com/magento/magento2/blob/develop/dev/tests/integration/… especialmente cuando lo combinas con un accesorio personalizado de tu módulo con un núcleo?
Kristof en Fooman
1
tbh todavía no lo probé pero parece un problema, sí. Puede ser necesario establecer la ruta de inclusión para que estos dispositivos funcionen.
Fabian Schmengler
1
@KristofatFooman Encontró una solución para los accesorios, ver actualización
Fabian Schmengler
Gran solución Puede haber un par de fallas aquí. En primer lugar, hay un error tipográfico: __DIR__debe ir seguido de una barra diagonal ( /_files). En segundo lugar, el dispositivo se carga desde TestFramework para que __DIR__realmente apunte al directorio TestFramework y no a su propio módulo. Se ComponentRegistrarpuede usar para esto:require $ObjectManager::getInstance()->get(ComponentRegistrar::class)->getPath('module', 'Foo_Bar').'/Test/Integration/_files/example.php';
Jisse Reitsma
10

He jugado un poco con las pruebas de integración, y esto es lo que he encontrado hasta ahora.

Básicamente, he seguido pasos similares a lo que dijo Fooman, con algunas diferencias para que la prueba de integración sea parte de mi módulo.

Estos son los pasos que seguí:

1- Coloca tus pruebas de integración debajo app/code/Vendor/CustomModule/Test/Integration

2- Copiar dev/tests/integration/phpunit.dist.xmladev/tests/integration/phpunit.xml

y reemplazar

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

con

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

3- Luego lo ejecuto usando la herramienta CLI bin/magento dev:test:run integration

Debe tener en cuenta lo que dice Fooman sobre "TESTS_CLEANUP" y el tiempo que lleva configurar las pruebas de integración si tiene habilitada la limpieza.

Aquí agrego un ejemplo funcional para mayor referencia. Verá cómo puede acceder al administrador de objetos y generar instancias de las clases de Magento, además de utilizar los accesorios de Magento.

app / code / Vendor / CustomModule / Controller / Order / 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 / Order / 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
fuente
Tenga en cuenta que su propia solución está bien y funciona, siempre que esté utilizando los accesorios del núcleo de Magento. Si desea usar sus propios accesorios, se topará con los problemas como se discutió anteriormente.
Jisse Reitsma