29 окт. 2018 г.
В этой статье речь пойдет про автоматическое тестирование в CMS Magento 2. Использовалась Magento 2.2
Общеизвесно, что magento достаточно сложная система сама по себе. Она требовательна к ресурсам. Разрабатывать под нее сложно и долго. В целом, у меня сложилось очень неоднозначное впечатление от ее использования.
Если мы делаем крупный проект на Magento с большим количеством самописных модулей, то, наверняка, в какой-то момент захочется писать автотесты.
Имеет смысл писать unit тесты на автономный функционал. Например, есть метод, который что-то считает на основании входных параметров. Unit тест для этого идеально подходит. Если же у нас есть метод, который работает с базой данных либо моделями magento, то, скорее всего, unit тесты нам здесь не очень помогут. Т.к. по сути нам придется подменить все зависимости, которых может быть много. И в реальности мы ничего особо не проверим. Вполне возможно, то, что мы хотели проверить как раз находится в этих самых зависимостях.
В этом случае мы создаем тестовую базу данных и пишем интеграционные тесты. Которые будут проверять весь функцинал в сборе. В основном для Magento 2 как раз актуальны интеграционные тесты.
Итак, приступим. Для начала нам нужно настроить окружение.
Общий служебный код, связанный с тестами находится в папке /dev/tests
Сначала настроим окружение для unit тестов. Тут все довольно просто. Достаточно скопировать конфигурационный файл.
cd /dev/tests/unit
cp phpunit.xml.dist phpunit.xml
У меня получился такой конфиг:
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/6.2/phpunit.xsd"
colors="true"
beStrictAboutTestsThatDoNotTestAnything="false"
bootstrap="./framework/bootstrap.php"
>
<testsuite name="Magento Unit Tests">
<directory suffix="Test.php">../../../app/code/*/*/Test/Unit</directory>
<directory suffix="Test.php">../../../lib/internal/*/*/Test/Unit</directory>
<directory suffix="Test.php">../../../lib/internal/*/*/*/Test/Unit</directory>
<directory suffix="Test.php">../../../setup/src/*/*/Test/Unit</directory>
<directory suffix="Test.php">../../../vendor/*/module-*/Test/Unit</directory>
<directory suffix="Test.php">../../../vendor/*/framework/Test/Unit</directory>
<directory suffix="Test.php">../../../vendor/*/framework/*/Test/Unit</directory>
<directory suffix="Test.php">./*/*/Test/Unit</directory>
</testsuite>
<php>
<ini name="date.timezone" value="America/Los_Angeles"/>
<ini name="xdebug.max_nesting_level" value="200"/>
</php>
<filter>
<whitelist addUncoveredFilesFromWhiteList="true">
<directory suffix=".php">../../../app/code/*</directory>
<directory suffix=".php">../../../lib/internal/Magento</directory>
<directory suffix=".php">../../../setup/src/*</directory>
<exclude>
<directory>../../../app/code/*/*/Test</directory>
<directory>../../../lib/internal/*/*/Test</directory>
<directory>../../../lib/internal/*/*/*/Test</directory>
<directory>../../../setup/src/*/*/Test</directory>
</exclude>
</whitelist>
</filter>
<listeners>
<listener class="Magento\Framework\TestFramework\Unit\Listener\ReplaceObjectManager"/>
</listeners>
<logging>
</logging>
</phpunit>
Все, теперь можно запускать тесты. Все тесты можно запустить такой командой:
./vendor/bin/phpunit -c dev/tests/unit/phpunit.xml
Правда тут есть проблема. Запускаются вообще все тесты, какие только возможно. В частности, стандартные тесты magento. Всего их около 20000. Тот факт, что команда разработки magneto пишет тесты не может не радовать. При этом все равно есть ощущение, что в системе достаточно багов. Из этих ~20000 тестов некоторые падают. Нет предела совершенству! Но главная проблема - работает все это довольно-таки долго. Мне ни разу не удалось дождаться, пока все тесты пройдут, даже на достаточно мощном железе. Вероятно, стандартные тесты имеет смысл запускать тем, кто разрабатывает саму Magento или конрибьютит в нее.
Нам же достаточно запустить тесты на собственный модуль. Это можно сделать такой командой:
./vendor/bin/phpunit -c dev/tests/unit/phpunit.xml app/code/{Vendor}/{Module}/Test/Unit
Запускает только наши тесты. Все тесты зеленые. Работает относительно быстро. Хотя, опять же, есть к чему стремиться.
Тут все несколько сложнее. Во-первых они медленные, как и сама Magento. Прогнать все тесты можно теоретически. Но реально это может занять бесконечное количество времени. К тому же здесь проверяется вся система в целом. И есть вероятность, что тесты не запустятся вообще. Например, если не настроено подключение к Rabit MQ. В лучшем случае, в помощь будет выброшено исключение. Поэтому также имеет смысл запускать тесты только на разрабатываемый модуль.
Настройка окружения достаточно хитрая. Описана в документации. У меня пролучилось настроить не сразу.
Сначала нужно скопировать конфигурационный файл:
cd /dev/tests/integration
cp phpunit.xml.dist phpunit.xml
Затем создать базу данных для тестов
CREATE DATABASE magento_integration_tests CHARACTER SET utf8 COLLATE utf8_general_ci;
Залить дамп основной базы в тестовую базу. Этот шаг нигде особо не описан. И, возможно, так делать не совсем правильно. Но если этого не делать, то тесты не запускаются. Вместо этого идут ошибки с отсутствующими таблицами. https://magento.stackexchange.com/questions/199114/magento-2-integration-test-cant-run-store-website-doesnt-exist
mysqldump -uroot -p -hlocalhost magento_db > magento_db.sql
mysql -uroot -p -D magento_integration_tests < magento_db.sql
Дальше нужно настроить подключение к тестовой БД.
Нужно скопировать и отредактировать файл /dev/tests/integration/etc/install-config-mysql.php.dist
Возможно нужно убрать неиспользуемые параметры. В моем случае - настройки rabitmq.
cp /dev/tests/integration/etc/install-config-mysql.php.dist /dev/tests/integration/etc/install-config-mysql.php
nano /dev/tests/integration/etc/install-config-mysql.php
Пример конфига:
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
return [
'db-host' => '127.0.0.1',
'db-user' => 'root',
'db-password' => '',
'db-name' => 'magento_220_ee_integration_tests',
'db-prefix' => 'prod_',
'backend-frontname' => 'backend',
'admin-user' => \Magento\TestFramework\Bootstrap::ADMIN_NAME,
'admin-password' => \Magento\TestFramework\Bootstrap::ADMIN_PASSWORD,
'admin-email' => \Magento\TestFramework\Bootstrap::ADMIN_EMAIL,
'admin-firstname' => \Magento\TestFramework\Bootstrap::ADMIN_FIRSTNAME,
'admin-lastname' => \Magento\TestFramework\Bootstrap::ADMIN_LASTNAME,
//'amqp-host' => '127.0.0.1',
//'amqp-port' => '5672',
//'amqp-user' => 'guest',
//'amqp-password' => 'guest',
];
Дальше мне пришлось отключить очистку базы.
nano /dev/tests/integration/phpunit.xml
Поменять параметр TESTS_CLEANUP
<const name="TESTS_CLEANUP" value="disabled"/>
Это тоже спорный момент. Возможно, это не лучший вариант. Однако без этого тесты у меня не запустились. Опять же, ругается на недостающие таблицы. Есть мнение, что очистка базы работает не совсем корректно. Необходимые таблицы просто не создаются. К тому же, наверняка, были бы проблемы с производительностью. Т.к база данных Magento достаточно тяжелая. И постоянная перезагрузка данных врядли будет быстро работать. Сейчас остается другая проблема. База общая для всех тестов. В результате можно нарваться на проблему, когда тесты влияют друг на друга. Частично можно решить с помощью фикстур и ручного обновления нужных данных перед тестами.
Теперь попробуем запустить тесты. Для этого перейдем в директорию с интерационными тестами.
cd dev/tests/integration
И запустим все тесты
../../../vendor/bin/phpunit
Скорее всего вы дождетесь выполнения нескольких тестов и на этом можно остановиться. Перейдем к следующему шагу. Запустим тесты для нашего модуля.
../../../vendor/bin/phpunit ../../../app/code/{Vendor}/{Module}/Test/Integration
../../../vendor/bin/phpunit ../../../app/code/{Vendor}/{Module}/Test/Integration/Model/OrderTest
Либо можно запустить один конкретный тест. Может быть очень полезно, т,к. запуск всех тетстов занимает довольно много времени.
../../../vendor/bin/phpunit ../../../app/code/{Vendor}/{Module}/Test/Integration/Model/OrderTest --filter {testLogin}
Ура! Тесты работают! Надеюсь, и у вас тоже... Дальше предлагаю рассмотреть процесс написания тестов для какого-нибудь модуля, кроме HelloWorld. Но там есть свои хитрости и это тема отдельной статьи. Еще раз напоминаю, что эта статья не является исчерпывающим руководством. Скорее это мой опыт написания тестов для Magento 2. Я допускаю, что-то здесь может быть не совсем правильно. В то же время, я думаю, что данный опыт поможет кому-то(например мне в будущем) сэкономить массу времени. На этом пока все. Спасибо за внимание!