Я разрабатываю плагин с использованием TDD, и одну вещь, которую я совершенно не могу проверить, это ... хуки.
Я имею в виду ОК, я могу проверить обратный вызов ловушек, но как я могу проверить, действительно ли ловушка срабатывает (как настраиваемые ловушки, так и ловушки WordPress по умолчанию)? Я предполагаю, что некоторые насмешки помогут, но я просто не могу понять, что мне не хватает.
Я установил тестовый набор с WP-CLI. Согласно этому ответу , init
крюк должен сработать, но ... это не так; также код работает внутри WordPress.
Насколько я понимаю, загрузчик загружается последним, поэтому имеет смысл не запускать init, поэтому остается вопрос: как, черт возьми, я должен проверять, запускаются ли перехватчики?
Благодарность!
Файл начальной загрузки выглядит так:
$_tests_dir = getenv('WP_TESTS_DIR');
if ( !$_tests_dir ) $_tests_dir = '/tmp/wordpress-tests-lib';
require_once $_tests_dir . '/includes/functions.php';
function _manually_load_plugin() {
require dirname( __FILE__ ) . '/../includes/RegisterCustomPostType.php';
}
tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );
require $_tests_dir . '/includes/bootstrap.php';
проверенный файл выглядит так:
class RegisterCustomPostType {
function __construct()
{
add_action( 'init', array( $this, 'register_post_type' ) );
}
public function register_post_type()
{
register_post_type( 'foo' );
}
}
И сам тест:
class CustomPostTypes extends WP_UnitTestCase {
function test_custom_post_type_creation()
{
$this->assertTrue( post_type_exists( 'foo' ) );
}
}
Благодарность!
источник
phpunit
, видите ли вы неудачные или пройденные тесты? Вы установилиbin/install-wp-tests.sh
?RegisterCustomPostType::__construct()
, никогда не вызывается, когда плагин загружается для тестов. Также возможно, что на вас повлияла ошибка # 29827 ; возможно, попробуйте обновить вашу версию пакета модульных тестов WP.bin/install-wp-tests.sh
(так как я использовал WP-АОН) @JD: RegisterCustomPostType :: __ конструкция будет называется (просто добавилdie()
заявление и PHPUnit останавливается там)did_action()
чтобы проверить, сработали ли действия.init
хука).Ответы:
Тест в изоляции
При разработке плагина лучший способ протестировать его без загрузки среды WordPress.
Если вы пишете код, который можно легко протестировать без WordPress, ваш код станет лучше .
Каждый компонент, который является модульным тестом , должен тестироваться изолированно : когда вы тестируете класс, вам нужно только протестировать этот конкретный класс, предполагая, что весь другой код работает отлично.
Это причина, почему модульные тесты называются «модульными».
В качестве дополнительного преимущества, без загрузки ядра, ваш тест будет выполняться намного быстрее.
Избегайте хуков в конструкторе
Совет, который я могу вам дать, это избегать использования хуков в конструкторах. Это одна из вещей, которая сделает ваш код тестируемым изолированно.
Давайте посмотрим тестовый код в OP:
И давайте предположим, что этот тест не пройден . Кто виноват ?
Как это можно улучшить?
Давайте предположим, что код вашего класса:
(Примечание: я буду ссылаться на эту версию класса для остальной части ответа)
То, как я написал этот класс, позволяет создавать экземпляры класса без вызова
add_action
.В классе выше есть 2 вещи для тестирования:
init
фактически вызываетadd_action
передачу ему правильных аргументовregister_post_type
фактически вызываетregister_post_type
функциюЯ не говорил, что вам нужно проверять, существует ли тип записи: если вы добавляете правильное действие и если вы вызываете
register_post_type
, пользовательский тип записи должен существовать: если он не существует, это проблема WordPress.Помните: когда вы тестируете свой плагин, вы должны тестировать свой код, а не код WordPress. В своих тестах вы должны предполагать, что WordPress (как и любая другая используемая вами внешняя библиотека) работает хорошо. В этом смысл модульного теста.
Но ... на практике?
Если WordPress не загружен, если вы попытаетесь вызвать методы класса выше, вы получите фатальную ошибку, поэтому вам нужно смоделировать функции.
«Ручной» метод
Конечно, вы можете написать свою библиотеку-макет или «вручную» макетировать каждый метод. Это возможно. Я скажу вам, как это сделать, но затем я покажу вам более простой способ.
Если WordPress не загружается во время выполнения тестов, это означает, что вы можете переопределить его функции, например,
add_action
илиregister_post_type
.Предположим, у вас есть файл, загруженный из файла начальной загрузки, где у вас есть:
Я переписал функции, чтобы просто добавлять элемент в глобальный массив при каждом вызове.
Теперь вы должны создать (если у вас его еще нет) свой собственный базовый класс тестовых случаев, расширяющий
PHPUnit_Framework_TestCase
: это позволяет вам легко конфигурировать ваши тесты.Это может быть что-то вроде:
Таким образом, перед каждым тестом глобальный счетчик сбрасывается.
А теперь ваш тестовый код (я имею в виду переписанный класс, который я разместил выше):
Вы должны отметить:
Хорошо .. но это ПИТА!
Да, если вам придется вручную издеваться над всеми функциями WordPress, это действительно больно. Несколько общих советов, которые я могу дать, - это использовать как можно меньше функций WP: вам не нужно переписывать WordPress, но абстрактные функции WP вы используете в пользовательских классах, чтобы их можно было смоделировать и легко протестировать.
Например, в отношении приведенного выше примера вы можете написать класс, который регистрирует типы записей, вызывая
register_post_type
init с заданными аргументами. С помощью этой абстракции вам все еще нужно тестировать этот класс, но в других местах вашего кода, которые регистрируют типы записей, вы можете использовать этот класс, высмеивая его в тестах (при условии, что он работает).Удивительная вещь: если вы напишите класс, который абстрагирует регистрацию CPT, вы можете создать для него отдельный репозиторий, и благодаря современным инструментам, таким как Composer, внедрите его во все проекты, где вам это нужно: протестируйте один раз, используйте везде . И если вы когда-нибудь найдете ошибку в ней, вы можете исправить ее в одном месте, и с помощью простого
composer update
все проекты, где она используется, тоже исправлены.Во второй раз: писать код, который можно тестировать изолированно, значит писать лучший код.
Но рано или поздно мне нужно где-то использовать функции WP ...
Конечно. Вы никогда не должны действовать параллельно с ядром, это не имеет смысла. Вы можете написать классы, которые обертывают функции WP, но эти классы тоже должны быть протестированы. Описанный выше «ручной» метод может использоваться для очень простых задач, но когда класс содержит много функций WP, это может быть проблемой.
К счастью, там есть хорошие люди, которые пишут хорошие вещи. 10up , одно из крупнейших агентств WP, имеет отличную библиотеку для людей, которые хотят правильно тестировать плагины. Это
WP_Mock
.Это позволяет вам смоделировать WP функции хуки . Предполагая, что вы загрузили в свои тесты (см. Репозиторий readme) тот же тест, который я написал выше, становится:
Просто, не правда ли? Этот ответ не является учебным пособием
WP_Mock
, поэтому прочтите readme-репозиторий для получения дополнительной информации, но я думаю, что приведенный выше пример должен быть достаточно ясным.Более того, вам не нужно писать какие-либо издевательства
add_action
илиregister_post_type
самостоятельно, или поддерживать какие-либо глобальные переменные.А WP классы?
В WP тоже есть некоторые классы, и если WordPress не загружается при запуске тестов, вам нужно их смоделировать.
Это намного проще, чем функции имитации, в PHPUnit есть встроенная система для имитации объектов, но здесь я хочу предложить вам Mockery . Это очень мощная библиотека и очень проста в использовании. Более того, это зависимость
WP_Mock
, поэтому, если она у вас есть, у вас тоже есть Mockery.Но как насчет
WP_UnitTestCase
?Набор тестов WordPress был создан для тестирования ядра WordPress , и если вы хотите внести свой вклад в ядро, оно является ключевым, но использование его для плагинов только делает тестирование не изолированным.
Посмотрите на мир WP: существует множество современных PHP-фреймворков и CMS, и ни один из них не предлагает тестировать плагины / модули / расширения (или как они там называются) с использованием кода фреймворка.
Если вы пропустите фабрики, полезную функцию пакета, вы должны знать, что там есть удивительные вещи .
Недостатки и недостатки
Есть случай, когда в предложенном мной рабочем процессе отсутствует: пользовательское тестирование базы данных .
Фактически, если вы используете для написания там стандартные таблицы и функции WordPress (на низкоуровневых
$wpdb
методах), вам никогда не нужно фактически записывать данные или проверять, действительно ли данные находятся в базе данных, просто убедитесь, что правильные методы вызываются с правильными аргументами.Однако вы можете написать плагины с настраиваемыми таблицами и функциями, которые создают запросы для написания там, и проверить, работают ли эти запросы, это ваша ответственность.
В этих случаях набор тестов WordPress может вам очень помочь, и в некоторых случаях может потребоваться загрузка WordPress для запуска подобных функций
dbDelta
.(Нет необходимости говорить, чтобы использовать другую базу данных для тестов, не так ли?)
К счастью, PHPUnit позволяет вам организовать ваши тесты в «наборы», которые можно запускать отдельно, так что вы можете написать набор для пользовательских тестов базы данных, в которых вы загружаете среду WordPress (или ее часть), оставляя все остальные ваши тесты без WordPress .
Обязательно пишите классы, которые абстрагируют как можно больше операций с базами данных таким образом, чтобы их использовали все другие классы плагинов, чтобы с помощью mock вы могли правильно протестировать большинство классов, не имея дело с базой данных.
В третий раз написание кода, легко тестируемого в отдельности, означает написание лучшего кода.
источник