PHPUnit для тестирования WordPress плагинов. Часть 2: Как писать свои тесты
В прошлой статье я рассказал о том, как установить PHPUnit в WordPress плагин. Теперь можно приступить к написанию тестов. Но перед этим рассмотрим зачем вообще нужно писать unit тесты
Главная цель – обеспечение стабильности кода во время его разрастания и усложнения. Грамотно написанные тесты позволят не переживать об уже написанном коде, ведь он точно будет рабочим как и прежде, а если это не так, то тесты покажут проблемные места. Хотя написание тестов и снижает скорость развития проекта на ранних этапах, но дает значительный этап на более поздних этапах разработки
Также наличие тестов один из показателей качества кода – плохой код почти невозможно покрыть тестами из-за запутанности и сильной связанности компонентом системы. Хотя даже покрытый тестами код может быть плохим
Не все unit тесты одинаково полезны для проекта и важно писать хорошие тесты. Хорошие – это те, которые дают как можно меньше ложных срабатываний и больше правильных. Больше об этом можно прочитать в книге Владимира Хорикова “Принципы юнит-тестирования”, а мы вернемся к PHPUnit
Unit тест должен проверять правильность работы одного юнита (единицы поведения) и делать это изолированно от других тестов. Для этого в PHPUnit есть класс TestCase
, который содержит всё необходимое для запуска тестов.
Предположим, что нам нужно протестировать класса Bar
. Для этого нужно создать класс BarTest
в директории с тестами, который будет расширять класс TestCase
, вот так:
class Bar {...}<br>class BarTest extends \PHPUnit\Framework\TestCase{...}
class Bar {...}
class BarTest extends \PHPUnit\Framework\TestCase{...}
Теперь пора написать какой-нибудь тест. Раз он первый, то пусть будет простым. Тестировать мы будем метод foo класса Bar
class BarTest extends \PHPUnit\Framework\TestCase{
public function testFoo() {
$bar = new Bar(); //1) Создание экземпляра класса
$x2 = $bar->foo(16); // 2) Вызов метода класса
$this->assertSame(32, $x2); 3)Проверка результата
}
}
Для проверки используется метод assertSame
из класса TestCase
. Первым параметром ему передается ожидаемое значение, а вторым результат работы. Запуск теста выведет следующую информацию:
OK (1 test, 1 assertion)
Ведь и правда 16 * 2 – это 32. Для проверки результата есть множество других методов: assertTrue и assertFalse для проверки на bool значения или assertEmpty для проверки массива на пустоту.
Больше об основах PHPUnit можно узнать в официальной документации, здесь ее подробно я пересказывать не буду, хотя к некоторым аспектам еще вернусь.
Теперь пора вспомнить, что мы пишем тесты под WordPress и у нас уже должна быть установлена WordPress Tests Library (далее WPTL). Теперь вместо \PHPUnit\Framework\TestCase
следует использовать WP_UnitTestCase
вот так:
class BarTest extends WP_UnitTestCase{...}
Запустив измененный тест мы не увидим изменений, но они конечно же есть. Класс WP_UnitTestCase
наследуется от WP_UnitTestCase_Base
, который содержит в себе 1630 строк на момент написания статьи. Самое заметное изменение в работе с тестами – это изменение нотации для написания кода. Теперь вместо camelCase мы все можем писать в snake_case, а по стандартам кода WordPress вообще обязаны.
Важные методы занимающие эти строки – это методы жизненного цикла, стандартный механизм PHPUnit, перед и после запуска каждого метода можно производить любые действия с помощью методов set_up
и tear_down
соответственно, а также перед и после запуска всех тестов в классе с помощью set_up_before_class
и tear_down_after_class
. С WPTL теперь нас будет меньше волновать:
- Подключение к БД
- Данные в БД
- Сущности созданные в процессе тестирования
- Фильтры и экшены
- Кеш
Также WPTL предоставляет класс WP_UnitTest_Factory
, экземпляр которого можно получить через метод ::factory
. Знакомые с паттерном фабрика уже поняли, что он делает, для остальных поясняю, этот класс позволяет создавать различные WP сущности: от постов и комментариев до отдельных блогов и их сетей. И это очень удобно, хотя и не понадобится для тестирования каждого плагина
Большинство оставшихся функций используется в жизненном цикле, хотя есть и полезные для отдельных тестов. Например, assertWPError
для проверки переменной на WP_Error
или go_to
, которая принимает url и выставляет все глобальные переменные так, как будто мы сейчас находимся на этой странице. Рекомендую изучить класс WP_UnitTestCase_Base
самостоятельно, он хорошо задокументирован и его чтение не будет сложным.
Кроме WP_UnitTestCase
есть и другие классы наследующиеся от WP_UnitTestCase_Base
. Я использовал только один и сомневаюсь, что остальные пригодятся когда-нибудь. Это класс WP_Ajax_UnitTestCase
– класс для тестирования AJAX запросов. Эмулирует вызов определенного action через вызов метода _handleAjax
и сохраняет вывод в свойство $_last_response
, на основе которого можно уже запускать тестовые методы
Правда появляется вопрос “насколько это unit тест?”. С одной стороны мы проверяем больше чем один unit – регистрацию и запуск обработчика, с другой регистрация и обработка сильно связаны и можно считать их единым целым.
Но самое интересное, что в документации WordPress все тесты с WPTL в плагинах и темах считаются интеграционными, а не unit, ведь для их запуска нужен WordPress, а значит они не самостоятельные. А вот тесты с WPTL в ядре считаются unit тестами, ведь тестируется независимый WordPress
Поэтому если далее я буду говорить не только про unit тесты, но и про интеграционные, не пугайтесь, в коде для нас это одно и тоже.
На этом на сегодня всё. В следующий раз разберем написание тестов на реалистичном примере WordPress плагина
Полезные ссылки:
Комментирование этой и других статей доступно в нашем Телеграм канале