|
| ||||||||||||
| ||||||||||||
|
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 метрик для каждого файла:
Столбец 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 |
|
CITForum © 1997–2025