PHPUnit и покрытие кода (Source code coverage)

Это третья заметка о 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.

Открываем в браузере индексный файл:

Переходим на ErrorController:

Я думаю по метрикам все понятно. Отображается сколько классов/методов/строк кода покрыто тестами в числовом и процентном соотношении.
На самом деле не все так плохо, но правильней буде добавить тест для метода 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. За прошедшую неделю я перелопатил довольно много информации и эта затея нравится мне все больше и больше.
Единственная просьба — пишите комментарии :). Мне интересны ваши фидбеки. Спасибо 😉

8 thoughts on “PHPUnit и покрытие кода (Source code coverage)

  1. А что ты собственно тестировать юнитами хочешь? Лично я не понимаю, как можно всерьез думать о покрытии тестами веб-приложения. На 90% оно не нужно, только на самописных классах, только на сложных функциях и т.п.

    Имхо, лучше сосредоточиться на функциональных тестах, чтобы тестировать сразу всё веб-приложение. Не знаю, можешь заюзать Силениум, может какой-то пыховский эмулятор браузера, в симфони есть достаточно удобный механизм функ тестирования.

    А.. И если пошла тема тестов взгляни на Behat – идея пришла с рубей, но кажется в Пыхе тоже имеет право на жизнь.

    • Думаю сервисный слой и модели нужно обязательно покрывать юнит тестами. Контроллеры можно покрывать по желанию или юнит тестами или функциональными тестами. Плагины и вью/экшн хелперы покрывать. Формы можно покрывать по желанию.

      Каждый сам определяет, что покрывать, а что нет. Но если следовать идеологии TDD, то непокрытого тестами кода быть не может.

      Все зависит от сайта. Я не собираюсь покрывать тестами сайты визитки. У нас есть проекты, где критические баги обойдутся дороже чем написание тестов.

      • Так я про то же, что TDD для вебдева обычно не канает.
        Даже если всё тестами покроешь всё равно что-то с ошибками может полететь.
        Слишком много зависимостей: БД, кешеры, html, и пр.

        Т.е. протестировав контроллер ты не можешь быть уверен наверняка, что во вьюшке всё будет выглядеть как надо.

        • Немного из личного опыта. Есть Restful API у проекта. Стараемся через TDD делать. И, скажу я, бывают ситуации, когда с внедрением чего-то нового старые тесты падают. И радуешься, когда узнаешь об этом сразу, на этапе разработке.

          Но вникать, обучаться писать понятные тесты – это труд. Полтора года, чувствую себя новичком.

  2. Прикольно. О CRAP не знал.

    Кстати, цикломатическую сложность высчитывает PHPMD.

    Идея использования CRAP мне нравится. Писать методы с высоким значением комплематической сложности плохо. Но если этого нельзя избежать – потрудись написать тесты на 100% покрывающие код.

    • к PHPMD ещё не добрался 🙂

      с остальным согласен. 100% не всегда реально/оправдано, но к этому нужно стремиться.

  3. У меня генерируются отчеты о покрытии когда, если я использую метод, описаный в https://github.com/sebastianbergmann/php-code-coverage. При запуске тестов с указанием параметров в командной строке или в phpunit.xml отчеты о покрытии кода создаются, но без данных. Понимаю, что нужно быть сильным телепатом, но все же, ЧЯДНТ?

Leave a Reply to mutogen Cancel reply

Your email address will not be published. Required fields are marked *