Создание интеграционных тестов для модулей Magento 2

27

Что касается моих потребностей в тестировании Magento 2, я использовал PHP Unit в качестве (более или менее) приемочного тестера - результаты тестирования серверных и HTML-запросов, внесенных в систему с моими установленными модулями. Я хотел бы иметь возможность создавать свои собственные интеграционные тесты. Позволяют ли инструменты тестирования, поставляемые с Magento 2, сторонним разработчикам создавать собственные интеграционные тесты, использующие код инфраструктуры тестирования Magento? Или мы все будем кататься сами?

То есть

  1. Я разработчик Magento
  2. Я хотел бы создать интеграционный тест
  3. Я хотел бы, чтобы в моем интеграционном тесте была полностью загруженная среда Magento для игры (т. Е. Использование менеджера объектов и / или внедрения зависимостей).
  4. Я бы хотел, чтобы мой интеграционный тест расширил его, Magento\TestFramework\TestCase\AbstractControllerчтобы у меня были те же помощники, что и в тестах Magento.
  5. Я хотел бы иметь возможность запускать свои тесты изолированно от остального набора тестов (т.е. не нужно ждать 2 часа, чтобы выполнить мои 15 секунд тестов)
  6. Я хочу, чтобы мои тесты хранились отдельно от тестов Magento

На сайте dev docs есть несколько начальных статей по тестированию, но они, похоже, ориентированы на запуск тестов, поставляемых вместе с Magento, а не на создание и запуск собственных тестов. Существуют старые образцы модулей , но все они расширяют PHPUnit_Framework_TestCaseкласс и кажутся модульными тестами (т. Е. Тестируют код, не зависящий от платформы Magento)

Есть ли у Magento способ сделать это?

Если нет, то кто-нибудь прокрутил свою собственную установку таким образом, чтобы тест сообщества разработчиков Magento мог принять ее в качестве стандарта?

Алан Сторм
источник

Ответы:

20

Это работает для нас, но мы еще не рассматривали возможность их перемещения в отдельное место по адресу 6.)

1.) Поместите свои интеграционные тесты под dev/tests/integration/testsuite/Vendor
2.) скопируйте dev/tests/integration/phpunit.dist.xml
в
dev/tests/integration/phpunit.xml

и заменить

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

с

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

3.) запустить его ../../../vendor/bin/phpunitили с ../../../vendor/bin/phpunit path/to/testsпомощью папки dev / test /gration

Обратите внимание, что интеграционные тесты занимают более 15 секунд, по крайней мере, при первом запуске, так как по сути устанавливает Magento. Вы можете сэкономить на последующих запусках, если вы используете

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

в вашем phpunit.xml

Кристоф в Фуман
источник
11

Я успешно разместил свои интеграционные тесты в отдельный каталог: src/My/Module/test/integration. Это может быть любой другой каталог, например app/code/My/Module/Test.

Добавьте их в новый набор тестов для тестирования интеграции Magento: Копировать dev/tests/integration/phpunit.xml.distв dev/tests/integration/phpunit.xmlи добавить следующее в <testsuites>узле:

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

Затем запустите такие тесты из dev/tests/integrationкаталога:

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

С помощью --testsuiteпараметра вы можете выбрать один набор тестов по имени, чтобы не все интеграционные тесты запускались одновременно

Обновление: Светильники

Чтобы использовать собственные приборы, потребовался небольшой обходной путь, поскольку Magento\TestFramework\Annotationбазовый каталог приборов определен глобально. Но, к счастью, Magento допускает и имена методов в качестве фиксаторов, поэтому работает следующее:

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

public static function loadFixture()
{
    include __DIR__ . '_files/something_fixture.php';
}
Фабиан Шменглер
источник
1
Не могли бы вы столкнуться с проблемами при использовании @magentoDataFixture здесь github.com/magento/magento2/blob/develop/dev/tests/integration/… особенно при объединении с пользовательским прибором из вашего модуля с основным?
Кристоф на Fooman
1
Я еще не пробовал, но это похоже на проблему, да. Возможно, потребуется установить путь включения, чтобы эти приборы работали.
Фабиан Шменглер
1
@KristofatFooman Нашел решение для светильников, смотрите обновление
Фабиан Шменглер
Отличное решение. Здесь может быть пара недостатков. Во-первых, это опечатка, __DIR__после которой следует косая черта ( /_files). Во-вторых, прибор загружается изнутри TestFramework, так что __DIR__фактически он указывает на каталог TestFramework, а не на ваш собственный модуль. ComponentRegistrarМогут быть использованы для этого:require $ObjectManager::getInstance()->get(ComponentRegistrar::class)->getPath('module', 'Foo_Bar').'/Test/Integration/_files/example.php';
Jisse Reitsma
10

Я немного поиграл с интеграционными тестами, и это то, что я нашел до сих пор.

По сути, я следовал шагам, подобным тому, что сказал Fooman, с некоторыми отличиями, чтобы сделать интеграционный тест частью моего модуля.

Вот шаги, которые я выполнил:

1- Поместите ваши интеграционные тесты под app/code/Vendor/CustomModule/Test/Integration

2- Копировать dev/tests/integration/phpunit.dist.xmlвdev/tests/integration/phpunit.xml

и заменить

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

с

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

3- Затем я запускаю его с помощью инструмента CLI bin/magento dev:test:run integration

Вы должны иметь в виду, что Fooman говорит о «TESTS_CLEANUP» и времени, которое требуется для настройки интеграционных тестов, если у вас включена очистка.

Здесь я добавлю функциональный пример для дальнейшего использования. Вы увидите, как вы можете получить доступ к диспетчеру объектов и сгенерировать экземпляр классов Magento, а также использовать приборы Magento.

Приложение / код / ​​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);
    }

}

Приложение / код / ​​Vendor / CustomModule / и т.д. / интерфейс / 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>

Приложение / код / ​​Vendor / CustomModule / и т.д. / 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>

Приложение / код / ​​Vendor / CustomModule / Test / Интеграция / 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']);
    }
}

Приложение / код / ​​Vendor / CustomModule / registration.php

\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Vendor_CustomModule',
    __DIR__
);
Факундо Капуа
источник
Обратите внимание, что ваше собственное решение в порядке, и оно работает, если вы используете крепления ядра Magento. Если вы хотите использовать свои собственные приборы, вы столкнетесь с проблемами, которые обсуждались ранее.
Джисс Рейтсма