Тестирование Python-приложений: от unittest к nose
С тех пор, как появилась первая библиотека для модульного тестирования — JUnit — появилась необходимость удобного выполнения тестов и представления результатов. В классическом JUnit были т.н. «runners», один для консоли, другой для графического режима. Современные Java-IDE обычно интегрируют процесс исполнения тестов обычно прямо в оболочку, благо в JUnit есть для этих целей API.
Когда в Python 2.1 появился модуль unittest его дизайн был фактически содран с JUnit, включая интерфейс нахождения тестов и TextRunner для выполнения тестов в консоли. Наверное любой Python-программист знаком с unittest.main(), assertEquals и unitest.TestCase. По крайней мере, у меня в Vim даже макросы есть специальные для набора этих повторяющихся конструкций.
Как это часто бывает с заимствованиями, удобство использования инструмента с «чуждой» идеологией оставляли желать лучшего. Одним не нравилось необходимость наследоваться от unitest.TestCase, другим — необходимость писать self.assertEquals() вместо привычного assert, третьим — негибкость в поиске и исполнении тестов.
В конце концов «терпець урвався» и на свет появилась первая реальная альтернатива unittest — py.test, как часть амбициозного проекта py lib. На мой взгляд, чересчур амбициозного, с невысокими шансами попасть в mainstream. Компонент py.test был и остается, пожалуй, самой популярной частью проекта.
Девиз py.test: «лучший API — его отсутствие». Как следствие, исчез класс TestCase от которого необходимо было наследоваться, вместе со своими assertEquals методами.
Наконец-то появилась возможность использовать обычный assert, а тесты определялись по наличию приставки test_ в именах функций и файлов.
Главных проблем с py.test было две: неудобство установки (требовался полный SVN checkout проекта py с последующими махинациями с PATH/PYTHONPATH) и «too much magic». Как я говорил, проект py был весьма «продвинутым» и использовал очень уж сомнительные «трюкачества» над интерпретатором. В результате иногда тесты не выполнялись или падали с какой-нибудь экзотической ошибкой.
Обе эти проблемы были решены при помощи nose. Эта поистине замечательная программка-кроха (<1,5KLoC) выполнена в лучших Unix-традициях: «do one thing and do it well». В двух словах это «py.test done right».
Магии в ней самый минимум, а устанавливается она при помощи сверх-удобной setuptools. В результате установки получаем скрипт «nosetests» который найдет и выполнит все наши тесты.
Помимо описанных выше функций, перешедших из py.test есть в ней и другие приятные мелочи, как-то: code coverage report (если установлен coverage.py), интеграция с doctest, «правильный» nosetest.main (оригинальный unittest.main использует sys.exit() что делает затруднительной интеграцию), package-level fixtures (определяются в __init__.py), интеграция с уже упомянутыми setuptools.
Собственно использование nose я решил оставить за рамками статьи т.к. документация описывает все что нужно.
P.S.: По большому счету, тестировать можно не только приложения написанные на Пайтоне, но практически это имеет смысл если Python уже используется каким-то образом. Например, когда тесты пишутся на Python, приложение на Си, а взаимодейстуют они через HTTP/командный интерфейс/API. Я, например, использую nose для тестирования веб-приложения при помощи twill.
Все про українське ІТ в телеграмі — підписуйтеся на канал DOU
4 коментарі
Підписатись на коментаріВідписатись від коментарів Коментарі можуть залишати тільки користувачі з підтвердженими акаунтами.