Покрытие кода тестами
Юнит-тесты хороши, когда покрывают весь ключевой код. Однако если проект чуть больше, чем “Hello, world!”, то оценить степень покрытия весьма проблематично. Существуют инструменты, которые помогают это делать. Для Python я знаю два таких:
- twisted.trial - каркас юнит-тестов, часть Twisted
- coverage.py - модуль Неда Бачелдера
twisted.trial
У команды trial есть опция coverage, после выполнения всех тестов во временном каталоге тестов появляется информация о покрытии кода тестами (по умолчанию искать нужно в _trial_temp/coverage). Имена файлов имеют вид package_name.module_name.cover. Каждый файл содержит строчки кода и счетчик, сколько раз каждая строка была выполнена. Ни разу не выполненные строки помечаются маркером >>>>>>.Т.е. никаких количественных оценок twisted.trial не дает, лишь визуально выделяет непротестированные участки кода. Правда, получить количественные оценки по этим результатам достаточно просто (достаточно подсчитать общее количество “помеченных” и “посчитанных” строк и взять от этого количества процентное соотношение к “помеченным”), странно что это не сделали разработчики. Еще один минус, который хочу отметить - необходимо использовать twisted.trial, а не unittest (т.е. во всех модулях юнит-тестов заменить import unittest на from twisted.trial import unittest). Ну и ставить целиком Twisted (а trial является его неразрывным компонентом) только ради того, чтобы померить покрытие кода, нецелесообразно.
coverage.py
coverage.py является более адекватным инструментом - ни от каких дополнительных библиотек он не зависит, может использоваться как из командной строки, так и из кода (как библиотека). Плюс к этому, он может выдавать как суммарный результат (в процентах), так и анотированный (т.е. копия исходного файла, в котором протестированная строка помечается >, не протестированная - !). В общем, must have. Ниже приведу пару советов по использованию.Из командной строки
Первый шаг - собирается информация по ходу выполнения юнит-тестов, собранная информация сохраняется в файле .coverage текущего каталога. Если ранее coverage.py уже запускался, то лучше сбросить ранее сохраненные данные (ключ -e)Второй шаг - по полученной информации создается суммарный отчет для указанного файла$ coverage.py -e $ coverage.py -x /path/to/unit/test_module.py
Если же хочется получить анотированный отчет, то для этого служит опция -a:$ coverage.py -r -m /path/to/module.py
и после этого, рядом с module.py появляется анотированный module.py,cover$ coverage.py -a /path/to/module.py
Ну и “живой” пример с PyTils:
$ coverage.py -e $ coverage.py -x /usr/local/lib/python2.4/site-packages/pytils/test/__init__.py testChoosePlural (pytils.test.test_numeral.ChoosePluralTestCase) ... ok [...] testProvideUnicode (pytils.test.test_utils.UnicodeTestCase) ... ok ---------------------------------------------------------------------- Ran 36 tests in 0.252s OK $ coverage.py -r -m /usr/local/lib/python2.4/site-packages/pytils/numeral.py Name Stmts Exec Cover Missing ------------------------------------------------------------------------------------- /usr/local/lib/python2.4/site-packages/pytils/numeral 138 136 98% 340, 365
Из кода
Использовать coverage.py из кода даже проще, чем из командной строки:и живой пример:>>> import coverage >>> coverage.erase() >>> coverage.start() >>> import yourmodule >>> youmodule.test.run() >>> coverage.stop() >>> coverage.report([yourmodule.foo, yourmodule.bar])
P.S. Нед говорит, что еще есть pycover и что в Sancho тоже можно покрытие кода померять, но я ни тот, ни другой не пробовал.>>> import coverage >>> coverage.erase() >>> coverage.start() >>> import pytils >>> pytils.VERSION '0.1.0-svn20061002' >>> pytils.test.run() .................................... ---------------------------------------------------------------------- Ran 36 tests in 0.207s OK >>> coverage.stop() >>> coverage.report([pytils.dt, pytils.numeral, pytils.translit, pytils.utils]) Name Stmts Exec Cover Missing ----------------------------------------------- pytils.dt 85 85 100% pytils.numeral 138 136 98% 340, 365 pytils.translit 38 37 97% 197 pytils.utils 34 32 94% 28-29 ----------------------------------------------- TOTAL 295 290 98%
Источники:
gorod-omsk.ru/blog/pythy/