3 часа назад
Что нового в PHPUnit 13.3


PHPUnit на данный момент является де-факто стандартом для написания тестов в экосистеме PHP. Он относится к семейству фреймворков xUnit (как JUnit или NUnit) и предоставляет инструменты для написания автоматизированных тестов.
В PHPUnit 13.3 развитие пошло по двум ключевым направлениям. Первое — усовершенствование работы с нестабильными тестами, второе — появление нового представления пространств имен и классов, а также еще несколько приятных бонусов в HTML-отчете. Поговорим о каждом направлении более подробно.
Обнаружение нестабильных тестов
Проверка, который то падает, то проходит, даже когда покрываемый код не менялся, вызывает не самые приятные чувства. Причин такого поведения может быть множество: от общего изменяемого состояния до недетерминированного порядка выполнения. Самый надежный метод выявить такие тесты оказался до смешного прост: запустить один и тот же тест множество раз подряд.
Вплоть до PHPUnit 9 существовала такая функция как --repeat. Тем не менее она повторяла весь набор тестов полностью, что делало ее более подходящей скорее для бенчмаркинга. Именно следовательно опцию сначала убрали, но затем из-за большого количества просьб все же вернули с одним «но»: теперь она повторяла не весь набор, а каждый отдельный тест.
Все новое — это хорошо забытое старое. Кажется, этой мудростью вдохновлялись разработчики. PHPUnit 13.3 берет уже готовую опцию и с помощью нее запускает определённый проверка до ста раз подряд через --repeat 100. Если какое-то из повторений заканчивается неудачей, оставшиеся повторения пропускаются. Каждое такое повторение выполняется как самостоятельный проверка и идентифицируется в выводе как (repetition N of M). Это помогает выявить и проблемы с утечками в коде, который управляет соединениями или кэшем, когда первые запуски проходят успешно, а проблемы появляются только при множественных вызовах.
С помощью атрибута #[Repeat] можно отметить отдельные тестовые методы. Он смоделирован по образцу аннотации @RepeatedTest из JUnit 5. Конструкцию #[Repeat] можно настраивать. Например, #[Repeat(100,5)] будет продолжать повторения, пока не будет зафиксировано 5 ошибок. Это полезно, если вас интересует именно паттерн отказов: как часто, в каких случаях, на каких повторениях падает тест. Стоит отметить, что такой порог не делает ошибки допустимыми — каждое неудачное повторение регистрируется и приводит к провалу теста.
А что делать с тестами, которые нельзя повторять? Возвращаемое значение тестового метода можно передать другим тестам через #[Depends], и его повторение привело бы к созданию нескольких, потенциально разных возвращаемых значений. Следовательно повторяются только те методы, которые явно объявляют void в качестве возвращаемого типа и не зависят от других тестов. При использовании --repeat все остальные тесты выполняются ровно один раз, как и до этого. Тем не менее если атрибут #[Repeat] установлен для метода, который не соответствует этим условиям, то PHPUnit выдаст предупреждение.

VDS-серверы от 200 ₽/месяц
Семь готовых конфигураций, KVM-виртуализация, NVMe SSD и техническая сопровождение 24/7.
Запустить в пару кликов →
Допустимость нестабильных тестов
Некоторые из тестов взаимодействуют с сетевыми сервисами, оборудованием или процессами, тайминги которых они не могут контролировать. В таком случае однократное падение теста ни о чем не скажет, а вот многократные — вполне. До сих пор перезапуск всей задачи в CI часто был единственным выходом, но это дорогое решение, которое к тому же не давало понять, какой именно тест вызвал проблему.
PHPUnit 13.3 предлагает решение лучше. Проверка с атрибутом #[Retry(3)] запускается до трех раз. Первая попытка, которая не завершилась ни провалом (failure), ни ошибкой (error) определяет итог. Пропущенная или незавершенная попытка точно так же завершает цикл. В соответствии с гарантией PHPUnit, которая звучит как «один экземпляр на каждый проверка», каждая такая попытка запускается на свежем экземпляре тестового класса. C опцией --retry это поведение применяется ко всем подходящим тестам на тех же условиях. Важно понимать, что совместное использование --repeat и --retry приведет к предупреждению, как и в случае с #[Retry] и #[Repeat] для одного и того же метода.
Можно было бы возразить против такого решения: встроенные повторы практически легализуют нестабильные тесты, а возникающее состояние гонки будет вечно проходить CI и никогда не будет исправлено. PHPUnit отвечает очень прозрачно: каждый тест, который прошел только после одной или нескольких неудачных попыток перечисляется в сводке вместе с количеством неудачных попыток. Проверка, исчерпавший все попытки, падает как любой иной, а проверка, прошедший с первой попытки, нигде не выводит информацию, связанную с повторами.
Покрытие кода через призму ваших классов
До сих пор HTML-отчет о покрытии кода показывал ваш код в том виде, в котором он хранится на диске, то есть в виде файлов и каталогов. Но это не весьма удобно — разработчик мыслит, как правило, классами, пространствами имен и методами.
Поэтому в отчет добавили классово-ориентированное представление, где каждая веб-страница теперь содержит две вкладки: с файлами и классами. Для первой ничего не поменялось, а вот вторая организует те же данные, но, что логично, по пространствам имен и классам. Эти два представления связаны между собой: со страницы исходного файла вкладка классов переведет вас прямо на страницу объявленного в нем класса, и наоборот.
Каждый класс получает свою собственную страницу со сводной таблицей метрик, включая индекс CRAP по методам, и аннотированным исходным кодом. Отображаются только те строки, которые принадлежат классу, а равным образом дополнительно добавлены отдельные разделы для каждого используемого трейта и метода, унаследованного от родительских классов. Таким образом, страница отвечает на вопрос: «Насколько хорошо протестирован этот класс?».
Важно отметить, что эти два представления намеренно агрегируют данные по-разному: в классо-ориентированном представлении исходник трейтов и родительских классов засчитывается в пользу просматриваемого класса, следовательно итоговые показатели могут отличаться от показателей файлового представления. Кроме того, такое представление генерируется по умолчанию и около удваивает размер отчета. Если нет необходимости в таком формате, его можно отключить через опцию --without-class-view.
Визуализация покрытия ветвей и путей
Теперь представление покрытия ветвей визуализирует точки принятия решений в коде. В новой колонке на полях, для каждой строки где происходит ветвление потока управления, отображается по одной точке на каждый возможный исход: цветом покрытого кода, если проверка выполнил этот исход, и цветом непокрытого кода в противном случае.
Это позволяет с первого взгляда заметить if, чей блок else никогда не выполняется, даже если сама строка кажется покрытой. Вместо повторения исходного кода каждой ветви теперь появилась компактная таблица по методам (по одной строке на каждую ветвь) и значок вроде 3/4 в заголовке каждого метода.
Представление покрытия путей было переработано аналогичным образом и дополнительно получило граф потока управления для каждого метода. Он отображает ветви метода в виде узлов, соединенных стрелками от входа до выхода, и раскрашенных зависимо от покрытия. При нажатии на строку в таблице путей соответствующий путь подсвечивается на графе, что точно демонстрирует, какой именно маршрут через метод описывает данный путь. Для рендеринга графов требуется утилита dot из Graphviz. Если она недоступна, отчет генерируется без графов. Ранее методы с более чем 100 путями вообще не отображались — теперь их первые 100 путей показаны в свернутом разделе наряду с примечанием, указывающим общее их количество.
Фильтрация покрытия кода по размеру тестов
С помощью атрибутов #[Small], #[Medium] и #[Large] вы теперь можете объявлять размер ваших тестов. PHPUnit всегда записывал эту информацию в данные о покрытии кода, но до сих пор HTML-отчет использовал её только для раскрашивания покрытых строк. Теперь для удобства на каждой странице каталога и файла отображается группа кнопок: Small, Medium, Large и All.
При выборе одного или нескольких размеров все цифры на странице пересчитываются: меняются полоски графиков, проценты и счетчики строк, методов и классов. Класс может показывать стопроцентное покрытие в общем и целом, даже если только малая его часть покрывается маленькими тестами, а остальное достигается только за счет больших end-to-end тестов. Один клик по Small покажет вам, что покрывают исключительно ваши юнит-тесты. При активном фильтре способ считается протестированным только тогда, когда тесты выбранных размеров полностью покрывают его самостоятельно, а класс считается протестированным, только если это справедливо для всех его методов.
Есть равным образом небольшой нюанс: All и комбинация Small, Medium, Large — это не одно и то же. All полностью игнорирует размеры тестов и учитывает каждую покрытую строку, а комбинация из трех размеров учитывает только те строки, которые покрыты хотя бы одним тестом с объявленным размером. Разница между ними показывает, какая часть покрытия обеспечивается тестами, у которых вообще не указан размер.
Вывод
Из нововведений понятно, что PHPUnit 13.3 эволюционирует в действительно ценный аналитический инструмент, чтобы помочь командам поддерживать порядок в крупных проектах с запутанной историей. Это позволит уменьшить неприятные ощущения от ложных срабатываний в CI/CD, а равным образом давать более корректную оценку качества кода.
Читают сейчас

1 час назад
Выпуск OpenRGB 1.0 — открытого проекта для управления RGB-подсветкой периферии
12 сентября 2026 года состоялся первый мажорный выпуск открытой утилиты OpenRGB. Проект даёт возможность управлять RGB-подсветкой материнских плат, видеокарт, клавиатур, кулеров, светодиодных лент и д

4 часа назад
Пополнение в семействах Zen 4 и Zen 3: новые процессоры Ryzen 5 7500 и Ryzen 5 5500F
AMD без громких анонсов обновила официальный каталог продукции, добавив в него два новых 6-ядерных решения начального уровня: Ryzen™ 5 7500 на базе архитектуры Zen™ 4 и Ryzen™ 5 5500F на базе архитект
5 часов назад
Предложена новая гипотеза, обосновывающая важную роль металлов в процессе зарождения жизни
В августовском номере журнала Science Advances вышла статья крупный группы авторов, предлагающая скорректированный в некоторых аспектах скрипт происхождения и ранней эволюции жизни. Читать далее
6 часов назад
Обновления Windows Server нарушили работу служб удалённых рабочих столов
Администраторы Windows сообщают, что накопительные обновления за сентябрь 2026 года вызывают сбои в работе служб удалённых рабочих столов (RDS) на системах Windows Server 2019, 2022 и 2025. Из‑за этог
6 часов назад
Рекомендации Минпросвещения по работе педагогов с ИИ исключают применение ИИ учениками начальной школы
По информации СМИ, методические рекомендации Минпросвещения России по работе педагогов с искусственным интеллектом исключают применение ИИ учениками начальной школы. В средних классах нейросети могут