Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
2011 г.

VIM + Devel::Cover — оценка степени покрытия Perl-кода тестами в одно касание

Александр Симаков

Введение

Значение инструментов для оценки степени покрытия кода тестами зачастую недооценивают: есть мнение, что если код и так хорошо покрыт, то отчёт всего лишь подтвердит и без того известный факт, ну а если кодовая база практически не протестирована, то скудные 5% покрытия навряд ли добавят оптимизма разработчикам.

На практике же, даже при нулевом изначальном покрытии, подобный инструмент способен стать серьёзным подспорьем в ежедневной работе: повысить эффективность труда и уменьшить количество дефектов.

В этой статье рассказывается об интеграции VIM-а и модуля Devel::Cover. Первоначальная настройка потребует некоторых усилий, однако этот труд многократно окупится в дальнейшей работе: после того, как создание отчёта станет вопросом нажатия пары кнопок, тестирование "невслепую" войдёт в привычку.

Devel::Cover на примере

Для начала, построим отчёт вручную. Итак, на входе имеем модуль Quux.pm и тест для него quux.t. Для запуска тестов с измерением степени покрытия, достаточно задать переменную окружения HARNESS_PERL_SWITCHES следующим образом (есть и другие способы, см. perldoc Devel::Cover):

export HARNESS_PERL_SWITCHES="-MDevel::Cover"

Затем запускаем тест (в этом примере предполагается, что и тест, и модуль находятся в одной папке, откуда и запускается команда prove):

prove quux.t

В результате, в текущей директории появится папка cover_db/ — база данных с информацией о покрытии кода. Для создания HTML-отчёта на основе этих данных необходимо запустить следующую команду (из той же директории):

cover

Вот как выглядит результат cover_db/coverage.html:

Видно, что в отчёт попал и сам тест quux.t. Для того, чтобы этого не происходило, достаточно передать команде cover опцию -ignore_re "[.]t$". В отчёте также фигурирует показатель степени покрытия кода документацией (pod-coverage). Если эта информация не нужна, то её также можно отключить (см. perldoc Devel::Cover, параметр -coverage).

В отчёте представлены 5 метрик для каждого файла:

  • stmt --- % выполненных строк кода
  • bran --- % выполненных ветвей условных операторов
  • cond --- % сработавших комбинаций в составных логических условиях
  • sub --- % выполненных подпрограмм
  • pod --- % подпрограмм, имеющих POD-документацию

Столбец time показывает, сколько времени прошло в каждом из файлов, а total — агрегирует перечисленные выше показатели.

Если навести мышью на ячейку, то появится всплывающая подсказка вида "N/M", где M — это общее количество тестируемых объектов (к примеру, для столбца stmt — это общее количество строк кода в файле), а N — количество протестированных объектов (для stmt — количество выполненных строк кода).

Если перейти по ссылке в ячейке, то будет показан подробный отчёт по данной метрике. Вот, к примеру, как в нашем примере выглядит bran-отчёт:

Красным отмечены невыполнившиеся ветви кода.

В завершение отмечу, что статистику несколько портит столбец sub, в котором, помимо подпрограмм, почему-то учитываются выражения вида use.

Стратегии тестирования

На практике, Devel::Cover можно использовать и как "телескоп", когда тесты пишутся с нуля для уже существующей кодовой базы, и как "микроскоп", когда необходимо тщательно проверить каждую веточку и условие в конкретном методе.

Отмечу, что достичь 100%-го sub-покрытия довольно просто, причём даже на нетривиальных модулях, чего не скажешь об остальных видах покрытия. Вообще, не стоит обманывать себя мыслью, что 100% покрытие кода даст 100%-ную защиту от дефектов. Во-первых, это не так, а во-вторых, достичь 100%-го bran- и cond-покрытия в реальной жизни бывает очень непросто.

Представьте себе ситуацию, когда в коде имеется проверка, которая по определению никогда не должна сработать и служит лишь последней линией обороны. Как правило, попасть в такую ветку без дополнительных ухищрений очень сложно. Понятно, что лучше иметь степень покрытия в 99.95% с этой проверкой, чем 100%, но без неё.

Ещё один факт, на который следует обратить внимание заключается в том, что показатель bran-покрытия не учитывает контекст. К примеру, пусть в методе имеются два отдельных условных оператора if(). Тест по-честному проверяет каждое из условий в состояниях TRUE и FALSE, что в результате даёт 100% bran-покрытие. Однако тест не проверяет, что будет, если условие в первом if-е вычислилось как TRUE, а во-втором — как FALSE в то время как это может иметь решающее значение для логики работы программы.

Таким образом, не стоит во чтобы то ни стало стремиться к заветным 100% во всех колонках: зачастую это неоправдано и к тому же всё равно не даёт никаких гарантий.

Ещё одно полезное применение Devel::Cover — помощь при ручном тестировании. Представьте себе большую монолитную, сильно-связанную программу, "вклиниться" в которую традиционными способами затруднительно. В такой ситуации построить отчёт можно следующим образом:

perl -MDevel::Cover yourprog args
cover

Автоматизация процесса

Следующим шагом автоматизируем запуск тестов, построение отчёта, открытие браузера и удаление временных файлов (если они больше не требуются). Скрипт test-coverage-report.pl осуществляет все вышеперечисленные операции.

Пример использования:

$ ./test-coverage-report.pl --input-file quux.t --browser-cmd=/usr/bin/google-chrome --browser-args '--new-window'

quux....ok
All tests successful.
Files=1, Tests=3,  2 wallclock secs ( 1.01 cusr +  0.04 csys =  1.05 CPU)
Reading database from /tmp/quux-qbIB


---------------------------- ------ ------ ------ ------ ------ ------ ------
File                           stmt   bran   cond    sub    pod   time  total
---------------------------- ------ ------ ------ ------ ------ ------ ------
Quux.pm                        94.3   87.5   80.0   87.5    0.0   46.0   86.4
quux.t                        100.0    n/a    n/a  100.0    n/a   54.0  100.0
Total                          97.3   87.5   80.0   94.7    0.0  100.0   92.7
---------------------------- ------ ------ ------ ------ ------ ------ ------


Writing HTML output to /tmp/quux-qbIB/coverage.html ...
done.
В текущем сеансе браузера создано новое окно.
Coverage report is generated in '/tmp/quux-qbIB'. Press 'Y' (default) to cleanup this directory or 'N' if you want to keep it. [Y]
Y
удален `/tmp/quux-qbIB/Quux-pm.html'
удален `/tmp/quux-qbIB/cover.12'
удален `/tmp/quux-qbIB/Quux-pm--condition.html'
удален `/tmp/quux-qbIB/cover.css'
удален `/tmp/quux-qbIB/structure/159a56006bd3bae11c68f2dfb7609a8d'
удален `/tmp/quux-qbIB/structure/7c2bd0b808c91b847c598f3960c48eee'
удален каталог: `/tmp/quux-qbIB/structure'
удален каталог: `/tmp/quux-qbIB/runs'
удален `/tmp/quux-qbIB/Quux-pm--branch.html'
удален `/tmp/quux-qbIB/Quux-pm--subroutine.html'
удален `/tmp/quux-qbIB/coverage.html'
удален каталог: `/tmp/quux-qbIB'

Для того, чтобы этот скрипт заработал, потребуется установить следующие Perl-модули:

Остальные зависимости являются built-in модулями.

Интеграция с VIM-ом

И, наконец, последний штрих: добавим в vimrc заклинание, вызывающие этот скрипт для текущего файла. Вот оно:

map ,c    <Esc>:!/path/to/test-coverage-report.pl --input-file % --browser-cmd=/usr/bin/google-chrome --browser-args='--new-window'<CR>
map ,C    <Esc>:!/path/to/test-coverage-report.pl --input-file % --browser-cmd=/usr/bin/google-chrome --browser-args='--new-window' --prove-args='--verbose'<CR>

Комбинация ,c запустит тест, построит отчёт, откроет заглавную страницу в браузере, а затем спросит, удалять сгенерированные файлы или нет. По умолчанию (просто ENTER) файлы будут удалены. Вариант ,C делает ровным счётом то же самое, но запускает prove в verbose режиме. Таким образом, для построения отчёта достаточно открыть vim-ом файл quux.t и нажать ,c.

Для ещё большей гибкости, можно написать свою обёртку для команды prove, которая, к примеру, может по имени Perl-модуля автоматически находить тест для него в определённой папке. Таким образом, ,c можно будет сказать как на самом модуле Quux.pm, так и на тесте для него quux.t даже не переключая буфер!

Выводы

Интеграция модуля Devel::Cover с VIM-ом выводит к кончикам пальцев очень мощный и полезный инструмент, который способен стать серьёзным подспорьем в каждодневной работе, а благодаря простоте и удобству, тестирование не вслепую очень быстро войдёт в привычку.

Ссылки

Приложение

Архив с тестовыми файлами, скриптом и отчётом: vim_plus_devel_cover_files.tar.gz

Новости мира IT:

Архив новостей

Последние комментарии:

С Новым Годом!! :) (1)
Среда 04.01, 04:47
Loading

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 985 1945361
Пресс-релизы — pr@citforum.ru
Обратная связь
Информация для авторов
Rambler's Top100 TopList liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2015 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...