Статья описывает отладку плагинов в тестовом окружении WordPress Testing Framework. Это значит, что в тестах можно будет пользоваться API WordPress, переключать роли пользователей сайта, автоматически создавать категории, посты, тэги, комментарии, вложения и тому подобное.
Последний раз проверено с PHP ^7.2, PHPUnit ^6.5, WordPress 4.9.8
Работает это так: в специальном файле bootstrap.php
, который указывается в конфиге phpunit.xml
, перед каждым запуском тестов загружается чистое ядро вордпресса (с тестовой базой данных и тестируемым плагином), и подключаются файлы тестового фреймворка, которые поставляют API для наших тестов.
Установка
Установить окружение можно автоматически и вручную. Автоматический способ быстрее, но мне больше нравится ручной путь, как способствующий большему контролю и пониманию процесса. Кроме того, у автоматического способа есть свои минусы, об этом ниже.
Далее все команды выполняются в корневой директории тестируемого плагина.
Автоматическая установка с WP-CLI
WP-CLI
— это удобный инструмент для управления сайтом из консоли (настройка опций, обновление плагинов и т.д.).
1 2 3 4 5 | curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar chmod +x wp-cli.phar sudo mv wp-cli.phar /usr/local/bin/wp wp --info # проверка |
(официальная документация по установке)
Команда установки тестового окружения:
1 2 | wp scaffold plugin-tests my-plugin |
Эта команда создаст несколько файлов:
- .travis.yml — конфиг Travis CI.
- phpcs.ruleset.xml — конфиг для
PHP_CodeSniffer
, стандарты оформления кода для утилитыphpcs
. - bin/install-wp-tests.sh — скрипт-установщик тестового ядра вордпресса.
Последний скрипт и нужно запустить (требуется установленная subversion):
1 2 3 4 5 | bash bin/install-wp-tests.sh wordpress_test root password localhost latest # Без создания БД # bash bin/install-wp-tests.sh wordpress_test root password localhost latest true |
- wordpress_test — название тестовой БД
- root — пользователь БД
- password — пароль пользователя
- localhost — хост MySQL-сервера
- latest — версия WordPress, может быть 4.7, 4.8 и так далее.
(подробно автоматическая установка описана в официальной документации)
Я доработал скрипт таким образом, чтобы он подхватывал параметры из переменных окружения:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/usr/bin/env bash # Если не указаны параметры, они по умолчанию берутся из переменных окружения DB_NAME="${1:-$TEST_TARGET_DB_NAME}" DB_USER="${2:-$TEST_WP_DB_USER}" DB_PASS="${3:-$TEST_WP_DB_PASS}" DB_HOST="${4:-$TEST_WP_DB_HOST}" WP_VERSION="${5:-$TEST_WP_VERSION}" #${5-latest} SKIP_DB_CREATE="${6:-$TEST_SKIP_DB_CREATE}" #${6-false} # Так работает официальный скрипт: если оставить эту часть, скрипт будет всегда ожидать аргументы из CLI #if [[ $# -lt 3 ]]; then # echo "usage: $0 <db-name> <db-user> <db-pass> [db-host] [wp-version] [skip-database-creation]" # exit 1 #fi ARGS_LIST=$(echo "db-user: ${DB_USER} db-pass: ${DB_PASS} db-name: ${DB_NAME} wp-version: ${WP_VERSION} skip-db-create: ${SKIP_DB_CREATE}") ARGS=( ${DB_USER} ${DB_PASS} ${DB_HOST} ${DB_NAME} ${WP_VERSION} ${SKIP_DB_CREATE} ) for arg in "${ARGS[@]}" ; do if [[ ${arg} == 'not-set' ]] ; then error "Not enough arguments: ${ARGS_LIST}" exit 1 fi done echo "Init with ${ARGS_LIST}" |
(отредактировать install-wp-tests.sh, вставить в начало файла)
Теперь нужно указать в файле ~/.profile параметры для тестов, и скрипт можно запускать без аргументов (то есть, не надо придумывать и добавлять в репозиторий файлы настроек вида *.conf.dist и т.д.).
1 2 3 4 5 6 7 8 | # Settings for WP Unit tests export TEST_WP_DB_USER=user export TEST_WP_DB_PASS=pa$$w0rD export TEST_WP_DB_HOST=localhost export TEST_SRC_DB_NAME=dbname export TEST_TARGET_DB_NAME=wordpress_test export TEST_WP_VERSION=latest # 4.9.8, ... export TEST_SKIP_DB_CREATE=true |
По-умолчанию файлы ставятся в /tmp, и, естественно, затираются после каждой перезагрузки — их приходится восстанавливать. Перед запуском скрипта можно указать пути установки через переменные окружения (описаны внутри скрипта), но установленный таким образом WP падал с ошибкой подключения каких-то нужных ядру файлов. Заблудившись в гугле в поиске решения этих проблем, я поставил всё вручную, и тесты заработали. Способ со значениями по умолчанию вполне рабочий, но на третий день заново скачивать тестовое ядро и править в нём конфиг надоедает.
Установка вручную
1 2 3 4 5 6 | mkdir /usr/local/wordpress-dev cd /usr/local/wordpress-dev # Скачать последнюю версию движка для разработчиков svn co http://develop.svn.wordpress.org/trunk/ |
В файлах движка можно найти README, который описывает дальнейшие шаги:
- Создать пользователя и базу данных в MySQL. Работает также копирование БД существующего сайта. НЕ рабочая БД: база данных будет очищена.
- Переименовать wp-tests-config-sample.php в wp-tests-config.php, внутри указать параметры подключения к БД.
- Обновить код командой:
svn up
- Запустить тесты движка:
phpunit
Если тесты проходят без ошибок, то окружение готово.
Настройка проекта
Установить в проект файлы фреймворка PHPUnit
:
1 2 | composer require --dev phpunit/phpunit ^|version| # ^6.5 в моём случае ./vendor/bin/phpunit --version |
(официальная документация по установке)
Тесты будут лежать в Test/WP/. Чтобы запускать phpunit
, нужно написать для него конфиг, в котором указать, какой файл загружать перед запуском тестов.
Пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <!--Test/WP/phpunit-wp.xml--> <phpunit bootstrap="bootstrap-wp.php" backupGlobals="false" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" > <php> <!-- Используется в тестах --> <const name="TEST_DOMAIN_URL" value="http://mydomain.local"/> </php> <testsuites> <testsuite> <!-- Запускать все файлы *Test.php --> <directory suffix="Test.php">./</directory> <!-- или вордпрессовские стандарты именования: --> <!--<directory prefix="test-" suffix=".php">./</directory>--> </testsuite> </testsuites> </phpunit> |
Файл phpunit-wp.xml лежит в директории тестов, а не в корне проекта, это удобно: не нужно фильтровать файлы других тестов (например, для Selenium
), там же подключается bootstrap-wp.php.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <?php // Test/WP/bootstrap-wp.php /** * Путь к тестам внутри чистой установки ядра * Этот и следующий параметры — также кандидаты на перенос в переменные окружения */ define('WP_TESTS_DIR', '/usr/local/wordpress-dev/trunk/tests/phpunit/'); /** * Путь к директории тестируемого плагина */ define('TEST_PLUGIN_PATH', '/srv/www/mysite.local/html/wp-content/plugins/myplugin/'); /** * Поставляет фильтр tests_add_filter */ require_once WP_TESTS_DIR . 'includes/functions.php'; /** * В этом колбэке подключается главный файл плагина, и по необходимости, всё остальное */ function _manually_load_plugin() { require TEST_PLUGIN_PATH . 'myplugin.php'; } tests_add_filter('muplugins_loaded', '_manually_load_plugin'); /** * Тестовое окружение WordPress */ require WP_TESTS_DIR . 'includes/bootstrap.php'; |
В моём случае плагин использует автозагрузку классов с дополнительной логикой, поэтому (скорее всего, из-за этого) в момент запуска падал, не найдя нужный класс. Проще всего оказалось сделать ссылку в директории тестового движка:
1 2 | ln -s /var/srv/www/vhosts/mysite.local/html/wp-content/plugins/myplugin/ /usr/local/wordpress-dev/trunk/src/wp-content/plugins/ |
В итоге, тесты запускаются с правильным конфигом:
1 2 | phpunit -c Test/WP/phpunit-wp.xml |
Тесты AJAX
Подробный туториал по написанию тестов AJAX можно найти здесь: WP Ajax Plugin Unit Testing.
У меня тесты падали с сообщением Undefined index: hook_suffix
в файле wp-admin/includes/class-wp-screen.php.
Исправлять придётся сам файл, в районе 217 строки нужно заменить начало метода get
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // wp-admin/includes/class-wp-screen.php:217 public static function get( $hook_name = '' ) { global $hook_suffix; // добавить if ( $hook_name instanceof WP_Screen ) { return $hook_name; } $post_type = $taxonomy = null; $in_admin = false; $action = ''; if ( $hook_name ) $id = $hook_name; else $id = $hook_suffix; // исправить $GLOBALS['hook_suffix'] |
Настройка composer
Чтобы не писать каждый раз в консоли команду для запуска тестов, добавим в composer.json секции scripts и scripts-descriptions.
1 2 3 4 5 6 7 8 9 10 11 | { // ... "scripts": { "test:wpunit": [ "./vendor/bin/phpunit -c Test/WP/phpunit-wp.xml --stop-on-failure" ] }, "scripts-descriptions": { "test:wpunit": "Run tests with WPUnit framework" } } |
Теперь тесты можно запускать так:
1 2 | # В корне проекта composer test:wpunit |
Дополнительно
- Automated Testing in WordPress — презентация с введением в юнит- и функциональное тестирование приложений (плагинов и тем) на WordPress. Примеры для phpunit, Selenium, WP_UnitTestCase.
- Writing WordPress Plugin Unit Tests — установка тестового окружения WordPress, описан процесс настройки конфигов phpunit и создание файла bootstrap.php. Примеры тестов.
Иллюстрация в шапке — Uehara Konen, Hatō zu 3.