Перейти к содержимому

Unit-тесты с PHPUnit для WordPress

Unit-тесты автоматически проверяют конкретную часть кода — обычно функцию или метод — в изоляции от остальной системы. В WordPress-разработке они помогают убедиться, что функции, классы и хуки работают корректно даже после изменений кода.

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

  • Unit-тесты: изолированные части кода, без внешних зависимостей
  • Интеграционные тесты: проверяют взаимодействие компонентов (например, плагин + БД WordPress) — именно их мы здесь рассматриваем, так как WP_UnitTestCase работает с реальной БД
  • Предотвращение регрессий — изменения не ломают существующую функциональность
  • Повышение надёжности — можно выпускать новые версии с уверенностью
  • Упрощение поддержки — новый разработчик видит, что его изменение ничего не сломало
  • Улучшение качества кода — тесты заставляют писать чище и переиспользуемее
  • Документирование — тесты показывают, как функция должна работать
  • PHP и MySQL (локально или через Docker)
  • База данных wordpress_tests с пользователем root и паролем root
  • SVN (Subversion) — для загрузки тестового окружения WordPress
  • WP-CLI — для генерации файлов тестов
Окно терминала
wp scaffold plugin-tests plugin-name --ci=github

Создаются файлы:

  • .github/workflows/phpunit.yml — интеграция с GitHub Actions
  • bin/install-wp-tests.sh — bash-скрипт установки тестового окружения
  • phpunit.xml.dist — конфигурация PHPUnit
  • tests/bootstrap.php — загрузка WordPress перед тестами
  • tests/test-sample.php — пример теста
Окно терминала
composer require --dev yoast/phpunit-polyfills:^1.0 wp-phpunit/wp-phpunit:^6.3
ПакетНазначение
wp-phpunit/wp-phpunitWordPress-тестовое окружение через PHPUnit (community-форк)
yoast/phpunit-polyfillsСовместимость между версиями PHPUnit и PHP

В composer.json:

{
"scripts": {
"test": "phpunit",
"test-install": "bash bin/install-wp-tests.sh wordpress_test root 'root' 127.0.0.1 latest"
}
}
Окно терминала
composer test-install

Удалите prefix="test-" из конфигурации — в некоторых версиях это вызывает конфликты. Создайте поддиректорию tests/Unit/ и переместите туда тесты.

define( 'TESTS_PLUGIN_DIR', dirname( __DIR__ ) );
define( 'UNIT_TESTS_DATA_PLUGIN_DIR', TESTS_PLUGIN_DIR . '/tests/Data/' );
if ( ! defined( 'WP_CORE_DIR' ) ) {
$_wp_core_dir = getenv( 'WP_CORE_DIR' );
if ( ! $_wp_core_dir ) {
$_wp_core_dir = rtrim( sys_get_temp_dir(), '/\\' ) . '/wordpress';
}
define( 'WP_CORE_DIR', $_wp_core_dir );
}

Добавьте в .gitignore:

.phpunit.result.cache
vendor/
Окно терминала
composer test

Ожидаемый результат:

PHPUnit 9.6.24 by Sebastian Bergmann and contributors.
OK (1 test, 1 assertion)

Основные утверждения для проверки результатов:

ФункцияПроверка
assertTrue($cond)Условие истинно
assertFalse($cond)Условие ложно
assertEquals($exp, $act)Равенство (нестрогое)
assertSame($exp, $act)Равенство (строгое: тип + значение)
assertNull($var)Переменная null
assertNotNull($var)Переменная не null
assertEmpty($var)Переменная пуста
assertNotEmpty($var)Переменная не пуста
assertCount($n, $arr)Массив содержит N элементов
assertContains($needle, $haystack)Значение есть в массиве/строке
assertInstanceOf($class, $obj)Объект — экземпляр класса
assertIsArray($var) / assertIsString($var) / assertIsInt($var)Проверка типа
assertGreaterThan($a, $b)Значение больше другого
assertLessThan($a, $b)Значение меньше другого
// Тестируемая функция
function plunit_sum( $a, $b ) {
return $a + $b;
}
// Тест с корректными данными
function test_sum_without_errors() {
$sum = plunit_sum( 4, 2 );
$this->assertEquals( 6, $sum );
}
// Тест с некорректными данными
function test_sum_with_errors() {
$sum = plunit_sum( 'hello', 2 );
$this->assertEquals( 0, $sum );
}

Важно: тестируйте не только корректные, но и некорректные входные данные. Функция должна безопасно обрабатывать строки, null и другие неожиданные значения.

Полноценный пример тестового класса:

class Test_Book_CPT extends WP_UnitTestCase {
public function setUp(): void {
parent::setUp();
// Регистрируем CPT перед каждым тестом
mtp_register_cpt_book();
flush_rewrite_rules();
}
// Проверка: CPT зарегистрирован
public function test_book_post_type_is_registered() {
$this->assertTrue(
post_type_exists( 'book' ),
'The "book" post type should be registered.'
);
}
// Проверка: CPT публичный и виден в админке
public function test_book_post_type_is_public() {
$post_type_obj = get_post_type_object( 'book' );
$this->assertNotNull( $post_type_obj );
$this->assertTrue( $post_type_obj->public );
$this->assertTrue( $post_type_obj->show_ui );
}
// Проверка: можно создать запись этого типа
public function test_can_create_book_post() {
$post_id = self::factory()->post->create( [
'post_type' => 'book',
'post_title' => 'Test Book',
] );
$this->assertIsInt( $post_id );
$this->assertSame( 'book', get_post_type( $post_id ) );
$this->assertSame( 'Test Book', get_the_title( $post_id ) );
}
}
  • extends WP_UnitTestCase — даёт доступ к WordPress-хелперам (factory()) и изоляции тестов
  • setUp() — вызывается перед каждым тестом. Регистрирует CPT и сбрасывает rewrite rules
  • self::factory()->post->create() — фабрика для создания записей напрямую в БД, минуя админку
  • post_type_exists() — WordPress-функция проверки регистрации CPT

Если плагин зависит от WooCommerce:

Окно терминала
install_woocommerce() {
local PLUGIN_DIR="$WP_CORE_DIR/wp-content/plugins"
mkdir -p "$PLUGIN_DIR"
WOOCOMMERCE_URL="https://downloads.wordpress.org/plugin/woocommerce.zip"
download "$WOOCOMMERCE_URL" "$TMPDIR/woocommerce.zip"
unzip -q "$TMPDIR/woocommerce.zip" -d "$TMPDIR/"
rm -rf "$PLUGIN_DIR/woocommerce"
mv "$TMPDIR/woocommerce" "$PLUGIN_DIR/woocommerce"
}
# Вызвать после install_wp
install_woocommerce
require_once WP_CORE_DIR . '/wp-content/plugins/woocommerce/woocommerce.php';

Файл .github/workflows/phpunit.yml (генерируется WP-CLI, требует доработок):

on:
pull_request:
branches:
- trunk # замените на вашу основную ветку
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
php-version: ['8.1', '8.2', '8.3']
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
tools: phpunit-polyfills:1.1
extensions: mbstring, xml, zip, intl, pdo, mysql
- name: Install SVN
run: sudo apt-get update && sudo apt-get install -y subversion
- name: Install WP tests
run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 latest
- name: Run tests
run: composer test

Временная установка WordPress неполная. Решение:

/var/folders/.../T/
# Узнайте директорию из вывода composer test-install
# Удалите и переустановите
rm -rfv /var/folders/.../T/wordpress-tests-lib/
rm -rfv /var/folders/.../T/wordpress/
composer test-install