PHPUnit остается бесспорным стандартом де-факто для модульного тестирования в экосистеме PHP. Однако с переходом на новые мажорные версии (особенно скачок с PHPUnit 8/9 на PHPUnit 10, а теперь и появление PHPUnit 11) процесс обновления может превратиться из рутинной задачи в источник головной боли. Устаревшие методы, измененные соглашения об именовании и новые архитектурные подходы требуют внимательного планирования. Эта статья — подробное руководство, которое поможет вам безопасно и эффективно обновить PHPUnit в вашем проекте, минимизировав риски и downtime.
Почему обновлять PHPUnit критически важно?
Откладывание обновления — это накопление технического долга, который со временем становится все дороже. Актуальная версия PHPUnit обеспечивает: совместимость с новыми версиями PHP (8.2, 8.3, 8.4), улучшенную производительность тестов, более чистый и выразительный синтаксис, лучшую интеграцию с современными инструментами (например, статическими анализаторами), актуальные исправления безопасности и, что немаловажно, доступ к документации и поддержке сообщества. Работа на устаревшей версии рано или поздно заблокирует обновление всего стека технологий проекта.
Подготовка к обновлению: Аудит и план
Прежде чем менять версию в `composer.json`, необходимо провести тщательную подготовку.
- Аудит текущего состояния. Выполните команду `./vendor/bin/phpunit --version` и изучите `composer.json`. Определите текущую мажорную версию и все прямые зависимости, связанные с тестированием (например, `mockery/mockery`, `prophecy/prophecy`). Проверьте, поддерживают ли они целевую версию PHPUnit.
- Изучите журнал изменений (CHANGELOG). Зайдите на официальный сайт phpunit.de или в репозиторий на GitHub. Внимательно изучите breaking changes для каждой мажорной версии между вашей текущей и целевой. Особое внимание уделите PHPUnit 10 и 11: именно в них произошли самые значительные очистки API.
- Обеспечьте надежное покрытие тестами. Убедитесь, что ваш текущий test suite проходит успешно (`./vendor/bin/phpunit`). Высокое покрытие (не обязательно 100%, но достаточное для ключевой логики) — ваша главная страховка при обновлении. Если тестов мало, рассмотрите возможность их наполнения перед миграцией.
- Создайте план отката. Используйте систему контроля версий (Git). Все изменения должны выполняться в отдельной feature-ветке. Убедитесь, что можете быстро вернуться к рабочему состоянию.
Рекомендуется выполнять обновление последовательно, мажорная версия за мажорной версией, особенно если прыжок значительный (например, с PHPUnit 7 на 11). Это упростит локализацию ошибок.
Шаг 1: Обновление зависимостей в `composer.json`. Измените версию `phpunit/phpunit` на желаемую, используя оператор `^` (например, `"phpunit/phpunit": "^11.0"`). Одновременно обновите связанные пакеты, такие как `phpunit/php-code-coverage`. Для PHPUnit 10 и выше пакет `phpspec/prophecy-phpunit` более не требуется, его можно удалить, если не используется явно.
Шаг 2: Установка новых версий. Выполните `composer update phpunit/phpunit --with-dependencies`. Флаг `--with-dependencies` обновит и связанные пакеты. Внимательно изучите вывод Composer на предмет предупреждений о несовместимости.
Шаг 3: Запуск тестов и анализ ошибок. После обновления запустите тесты. Скорее всего, вы столкнетесь с ошибками. Не паникуйте — это ожидаемо. Систематизируйте их.
Типичные проблемы и их решения
- Устаревшие аннотации -> Атрибуты. Это самое масштабное изменение в PHPUnit 10. Аннотации в комментариях `/** @test */`, `/** @covers */`, `/** @dataProvider */`, `/** @depends */` больше не поддерживаются. Их необходимо заменить на атрибуты PHP 8.
Было: `/** @dataProvider dataProviderName */`
Стало: `#[DataProvider('dataProviderName')]`
Использование атрибутов делает код чище и является современным стандартом.
- Изменение имен классов и методов. Многие методы, помеченные как устаревшие в 9-й версии, удалены в 10-й.
* Класс `PHPUnit\Framework\TestCase` — это единственный правильный класс для наследования. Устаревшие псевдонимы удалены.
- Конфигурация XML (`phpunit.xml`). Схема конфигурации обновляется. Устаревшие атрибуты и элементы (например, `checkForUnintentionallyCoveredCode`, `verbose`) могут быть удалены или заменены. Лучший подход — сгенерировать свежий конфигурационный файл с помощью команды `./vendor/bin/phpunit --generate-configuration` и аккуратно перенести в него свои настройки.
- Моки и стабы. Если вы используете Prophecy (который был встроен ранее), в PHPUnit 10+ его поддержка убрана из ядра. Вам нужно либо перейти на встроенный фреймворк моков PHPUnit (который значительно улучшился), либо явно установить `phpspec/prophecy-phpunit` и использовать соответствующий trait. Встроенный мок-билдер PHPUnit теперь предпочтительнее.
- Кастомизация вывода. Классы, расширяющие `PHPUnit\TextUI\DefaultResultPrinter`, потребуют переработки, так как внутренняя архитектура вывода изменилась.
Для больших проектов ручная правка тысяч тестов нереальна. К счастью, существуют инструменты автоматизации.
* Rector: Мощный инструмент для рефакторинга PHP-кода. Существуют готовые наборы правил (rulesets) для миграции с PHPUnit 9 на 10 и с 10 на 11. Установите Rector, настройте `rector.php` и запустите анализ — инструмент покажет, что можно исправить автоматически, и сделает это.
* PHPUnit Migrations: Скрипты, предлагаемые самим PHPUnit (в репозитории есть папка `migrations`), но их возможности ограничены по сравнению с Rector.
Использование этих инструментов может сэкономить десятки часов работы, но после автоматического исправления обязателен тщательный ручной ревью изменений.
Лучшие практики после обновления
- Обновите конвейер CI/CD. Убедитесь, что в ваших сценариях сборки в GitLab CI, GitHub Actions или Jenkins используется обновленная версия PHPUnit.
- Приведите код к современному стилю. Используйте возможность заменить все аннотации на атрибуты. Это улучшит читаемость.
- Рассмотрите возможность отказа от `setUp()` и `tearDown()` в пользу `setUpBeforeClass()`/`tearDownAfterClass()` или еще лучше — использования `#[Before]`, `#[After]`, `#[BeforeClass]`, `#[AfterClass]` атрибутов для более тонкого контроля.
- Изучите новые возможности. Актуальные версии PHPUnit предлагают новые утверждения (assertions), улучшенную работу с исключениями, лучшую интеграцию. Потратьте время на изучение документации, чтобы писать более лаконичные и мощные тесты.
Обновление PHPUnit — это инвестиция в стабильность, производительность и поддерживаемость вашего проекта. Хотя процесс требует времени и внимания, системный подход, использование инструментов автоматизации и следование лучшим практикам сведут риски к минимуму. Не откладывайте это на потом: регулярные обновления малыми шагами гораздо менее болезненны, чем один гигантский скачок через несколько лет. Современный PHPUnit — это быстрее, чище и надежнее, и он того стоит.
Комментарии (9)