Это третья заметка о continuous integration (CI). В ней я затрону такое понятие как покрытие кода. Это одна из мер качества ПО, которая отображает какой процент исходного кода проверяется при запуске тестов.
PHP_CodeCoverage
PHP_CodeCoverage — утилита написанная Sebastian Bergmann. Она используется в составе PHPUnit и именно благодаря ей (и xDebug) PHPUnit умеет генерировать отчет по code coverage.
Доступно три формата отчетов:
--coverage-html <dir> Generate code coverage report in HTML format. --coverage-clover <file> Write code coverage data in Clover XML format. --coverage-source <dir> Write code coverage / source data in XML format. |
Начнем с HTML.
Есть два пути:
первый путь – прописать в phpunit.xml секцию которая отвечает за генерацию отчета по code coverage:
<logging> <log type="coverage-html" target="./log/report" charset="UTF-8" yui="true" highlight="true" lowUpperBound="50" highLowerBound="80"/> </logging> |
второй – запустить phpunit с ключем –coverage-html
/var/www/test/hudson/tests $ phpunit --coverage-html ./logs/coverage application/ |
Мне больше нравится первый :).
Поэтому я добавил соответствующие настройки в phpunit.xml => см. листинг.
Запускаем тесты:
/var/www/test/hudson/tests $ phpunit PHPUnit 3.4.13 by Sebastian Bergmann. .. Time: 2 seconds, Memory: 18.75Mb OK (2 tests, 7 assertions) Generating code coverage report, this may take a moment. |
В директории /var/www/test/hudson/tests/logs/coverage/ должны появится файлы сгенерированные PHP_CodeCoverage.
Открываем в браузере индексный файл:
Я думаю по метрикам все понятно. Отображается сколько классов/методов/строк кода покрыто тестами в числовом и процентном соотношении.
На самом деле не все так плохо, но правильней буде добавить тест для метода getLog() и проверять 500ю ошибку и вывод error_hendler.
PHPUnit 3.5 & CRAP
В процессе работы над заметкой узнал, что в PHPUnit 3.5 добавился расчет CRAP (Change Risk Analysis and Predictions) (“crap” это “дерьмо” в переводе с английского). На Хабре есть краткий обзор этой метрики.
Формула с недвусмысленным названием CRAP позволяет оценить, воскликнет ли разработчик «Oh crap!» узнав, что за код ему выпало счастье поддерживать.
На локальной машине я ставил PHPUnit с пакетов. Версия 3.4.13. Нужно обновить PHPUnit до 3.5 и удобней всего это сделать через PEAR:
$ sudo pear upgrade phpunit/PHPUnit ... ... ... upgrade ok: channel://pear.phpunit.de/Text_Template-1.1.0 upgrade ok: channel://pear.phpunit.de/PHPUnit_Selenium-1.0.1 upgrade ok: channel://pear.symfony-project.com/YAML-1.0.4 upgrade ok: channel://pear.phpunit.de/PHP_TokenStream-1.0.1 upgrade ok: channel://pear.phpunit.de/DbUnit-1.0.0 upgrade ok: channel://pear.phpunit.de/PHP_CodeCoverage-1.0.2 upgrade ok: channel://pear.phpunit.de/PHPUnit_MockObject-1.0.3 upgrade ok: channel://pear.phpunit.de/PHPUnit-3.5.5 |
Небольшой оффтоп, но кому-то может оказаться полезным :).
Запускаю phpunit и получаю обновленный отчет:
Видим, что от errorAction() все таки “попахивает”.
Ещё одно нововведение это Code Coverage Dashboard (ссылка есть на индексной странице отчета), на которой в удобном для восприятия виде отображается итоговая информация по нескольким параметрам:
- Class Coverage Distribution – график показывает сколько класов и насколько покрыты тестами
- Class Complexity – по оси X покрытие, а по оси Y сложность классов
- Top Project Risks – наиболее рисковые места проекта (по CRAP)
- Least Tested Methods – методы, которые проверяются хуже всех
С 2мя тестами на zf-sample здесь особо смотреть нечего…
Лучше посмотреть на Dashboard по PHPUnit:
Se deberá mantener
На этом пока все. В след. заметке я напишу о тасках для генерации отчетов по code coverage в Phing и последующем их выводе в Hudson.
PS. За прошедшую неделю я перелопатил довольно много информации и эта затея нравится мне все больше и больше.
Единственная просьба — пишите комментарии :). Мне интересны ваши фидбеки. Спасибо 😉
А что ты собственно тестировать юнитами хочешь? Лично я не понимаю, как можно всерьез думать о покрытии тестами веб-приложения. На 90% оно не нужно, только на самописных классах, только на сложных функциях и т.п.
Имхо, лучше сосредоточиться на функциональных тестах, чтобы тестировать сразу всё веб-приложение. Не знаю, можешь заюзать Силениум, может какой-то пыховский эмулятор браузера, в симфони есть достаточно удобный механизм функ тестирования.
А.. И если пошла тема тестов взгляни на Behat – идея пришла с рубей, но кажется в Пыхе тоже имеет право на жизнь.
Думаю сервисный слой и модели нужно обязательно покрывать юнит тестами. Контроллеры можно покрывать по желанию или юнит тестами или функциональными тестами. Плагины и вью/экшн хелперы покрывать. Формы можно покрывать по желанию.
Каждый сам определяет, что покрывать, а что нет. Но если следовать идеологии TDD, то непокрытого тестами кода быть не может.
Все зависит от сайта. Я не собираюсь покрывать тестами сайты визитки. У нас есть проекты, где критические баги обойдутся дороже чем написание тестов.
Так я про то же, что TDD для вебдева обычно не канает.
Даже если всё тестами покроешь всё равно что-то с ошибками может полететь.
Слишком много зависимостей: БД, кешеры, html, и пр.
Т.е. протестировав контроллер ты не можешь быть уверен наверняка, что во вьюшке всё будет выглядеть как надо.
Немного из личного опыта. Есть Restful API у проекта. Стараемся через TDD делать. И, скажу я, бывают ситуации, когда с внедрением чего-то нового старые тесты падают. И радуешься, когда узнаешь об этом сразу, на этапе разработке.
Но вникать, обучаться писать понятные тесты – это труд. Полтора года, чувствую себя новичком.
Прикольно. О CRAP не знал.
Кстати, цикломатическую сложность высчитывает PHPMD.
Идея использования CRAP мне нравится. Писать методы с высоким значением комплематической сложности плохо. Но если этого нельзя избежать – потрудись написать тесты на 100% покрывающие код.
к PHPMD ещё не добрался 🙂
с остальным согласен. 100% не всегда реально/оправдано, но к этому нужно стремиться.
Хорошая статья. Тоже узнал о CRAP.
У меня генерируются отчеты о покрытии когда, если я использую метод, описаный в https://github.com/sebastianbergmann/php-code-coverage. При запуске тестов с указанием параметров в командной строке или в phpunit.xml отчеты о покрытии кода создаются, но без данных. Понимаю, что нужно быть сильным телепатом, но все же, ЧЯДНТ?