Лучшая практика для юнит-тестов в Magento 1.9

11

Я поддерживаю сайт Magento 1.9 с несколькими пользовательскими модулями. Некоторые функциональные возможности критичны для бизнеса и остро нуждаются в некоторых модульных тестах. Например, калькулятор цены за единицу.

Я обычно разрабатываю в Symfony и действительно предпочел бы как-нибудь использовать PHPUnit (w / Composer), если это вообще возможно.

Некоторые функции основаны на данных, импортированных в несколько пользовательских таблиц базы данных, поэтому я бы предпочел как-то загрузить данные.

Поэтому я ищу лучший подход к написанию некоторых модульных тестов. Я с удовольствием приму уроки или что-то подобное. Любая помощь приветствуется.

Фригг
источник

Ответы:

10

Я столкнулся с той же проблемой некоторое время назад.

Я подумал об использовании модуля Ecomdev PHPUnit, но мне трудно его использовать и он плохо документирован (но мне все еще нравится то, что делает Иван, и его большой вклад в экосистему Magento).

Итак, с помощью Vinai я разработал следующий модуль тестового фреймворка: https://github.com/digitalpianism/testframework

Первоначальная цель была для интеграционных тестов, но я использую его и для юнит-тестов. Вы можете увидеть это в действии здесь: https://github.com/digitalpianism/easytoplinks/blob/master/app/code/community/DigitalPianism/EasyToplinks/Test/Unit/Block/Page/Template/LinksTest.php

Что касается фикстур, я использую откаты транзакций, чтобы избежать создания образцов данных в базе данных.

Рафаэль в цифровом пианизме
источник
Это выглядит действительно многообещающе. Я попробую это. Спасибо.
Фригг
13

Монтаж

Поскольку Magento 1 не использует композитор из коробки, я не думаю , что это имеет большое значение , если установить PHPUnit с помощью композитора или просто скачать Фары версию.
Если вы уже используете composer для управления сторонними модулями или библиотеками на вашем сайте, то, вероятно, в этом есть смысл. Если вы не используете PHP7, вы будете ограничены старой версией phpunit (вот почему я ссылался на версию 4.8 выше).

Интеграционные тесты против / и / или модульные тесты

Поскольку Magento 1 является настолько тяжелым приложением, имеет смысл разделить загрузчик phpunit на один для интеграции и один для модульных тестов.
Для начальной загрузки модульного теста требуется только инициализация автозагрузчика, а для начальной загрузки интеграционного теста требуется инициализация всей среды приложения, включая загрузку конфигурации и соединение базы данных.
Из-за этого интеграционные тесты в Magento имеют тенденцию выполняться намного медленнее, чем модульные тесты (даже в большей степени, чем в других приложениях).

Начальная загрузка Magento в phpunit

  • Автозагрузчик Magento не совместим с PSR-0, поскольку выдает исключение, если не может найти файл, в котором находится класс. Это нарушает некоторые class_existsспособы использования в phpunit. Есть несколько возможных (если хакерских) обходных путей:

    • Отмените регистрацию автозагрузчика Magento, обернув его \Varien_Autoload::autoload()в декораторе, игнорируя возникающие исключения, и зарегистрируйте обертку как новый автозагрузчик. Это имеет низкую вероятность конфликтов со сторонними библиотеками, которые регистрируют автозагрузчики и зависят от определенного порядка автозагрузчика.
    • Используйте пользовательский обработчик ошибок, заключающий в себе встроенный в Magento 1. Пользовательский обработчик ошибок проглатывает ошибки, вызванные автозагрузчиком Magento. Это решение, которое использует тестовая среда Рафаэля . Кажется, это наиболее совместимо с другими сторонними расширениями.
    • Используйте взломать путь включения, чтобы переопределить, \Varien_Autoload::autoload()чтобы не выдавать ошибку, если файл не существует. Это, однако, конфликтует с несколькими модулями, которые также перекрывают один и тот же класс. Я не использую этот подход сам.
  • Чтобы избежать ошибок в сеансе, запускаемом во время тестов, просто задайте его $_SESSON = []в начальной загрузке.

  • Установите пользовательский объект ответа через Mage::app()->setResponse($testResponse)который расширяет реальный объект , но не отправляет выходные данные или заголовки.

  • Для повторной инициализации Magento между интеграционными тестами, которые полностью изменяют состояние времени выполнения, используйте Mage::reset(); Mage::app(). Обратите внимание, что после этого обработчик ошибок должен быть перекрашен.

арматура

Для осветителей DB я обычно использую обычные модели в методах осветителей для создания осветителей, например createSimpleProduct($sku). Как сказал Рафаэль, используйте setUp()и, tearDown()чтобы обернуть тест в транзакцию, которая откатывается после теста (например Mage::getSingleton('core/resource')->getConnection('default_setup')->beginTransaction()).

Для приборов конфигурации магазина я стараюсь использовать только встроенные в память приборы Mage::app()->getStore()->setConfig($path, $value).

EcomDev_PHPUnitРасширение также предоставляет возможность для создания БД приборов с помощью YAML файлов, но для себя я считаю , тем труднее поддерживать по сравнению с сантехникой , созданной с использованием модели классов. YMMV.

Test Doubles

Реестр может быть использован для вставки тестовых двойников для объектов, созданных с помощью Mage::getSingleton(), Mage::getResourceSingleton()и Mage::helper().
Некоторые другие центральные объекты могут быть установлены Mage::app()(например, запрос).
Чтобы заменить классы, созданные с помощью Mage::getModel()или Mage::getResourceModel()с тестовыми двойниками, необходимо использовать пользовательскую оболочку объекта конфигурации . Посмотрите этот пример в тестовой среде Рафаэля, как это можно сделать.

Резюме

Как только Magento загружается, почти все можно довольно хорошо протестировать. Будьте готовы создавать глубокие макеты из-за большого количества цепочек методов, используемых в основном коде.
Несмотря на то, что настройки не очень удачные, они хорошо работают, и я считаю, что тесты придают мне большую уверенность и ценность, в значительной степени сопоставимые с набором тестов для приложения Symphony.

Vinai
источник
Я никогда не пробовал, но почему бы не использовать Magento Test Framework? ( docs.magento.com/m1/ce/user_guide/magento/… )
Фра
3
Да, я пробовал, но это функциональное тестирование (не единичное или интеграционное), оно медленное, сложное и тесты, как правило, ненадежные и хрупкие. В целом, я считал время, проведенное с ним, пустой тратой времени.
Vinai
@ Vinai Я знаю, что уже поздно, но обычно в контроллере есть вызовы моделей и коллекций, которые при тестировании нам не понадобятся. Я использую вашу платформу тестирования (DigitalPianism), и там мы можем TestDouble модели, но, делая запрос get к действию контроллера, который, в свою очередь, использует модель, как я могу издеваться над вызовом модели / коллекции?
arqam