Публикации с меткой «nose»

Блог django на хабрахабре

Django Framework / HowTo по continuous integration проекта на Django с помощью TeamCity

Введение


В процессе разработки, создавая новый функционал, всё чаще широкими мазками стал задевать старый код чем разрушал логику его работы. Это заставило всё-таки написать юнит и интеграционные тесты для старого кода и автоматизировать их запуск, т.к. гонять руками все тесты как-то грустно. Как раз вспомнилось недавнее руководство по CI Django в Jenkins и довольно старое по Webtest в Django. В итоге была совершена попытка поднять Дженкинса, но он как-то на моей убунте не взлетел и я грешным делом вспомнил про TeamCity. «Раз уж пишу в PyCharm и нашёл к нему подход, то, наверно, и TeamCity осилю, ведь конторка-то одна!» — подумалось мне… В общем-то я оказался прав, и, пока мне позволяет карма, решил подарить вам ультраполезный (и мегаподробный), в отличие от моего предыдущего, мануал :)

Итого: кому требуется руководство по поднятию интеграционного сервера TeamCity, и тестирование в нём Django проектов c тестами nose и webtest в виртуальном окружении python с автоматическим его (окружения) обновлением — добро пожаловать под кат.

Осторожно! Для работы TeamCity требуется (согласно документации) sun/oracle версия JVM…

Блог python на хабрахабре

Python / Непрерываное тестирование питонопроекта

Программист зверь ленивый, поэтому всё, что будет делаться больше одного раза надо непременно заскриптовать.

Я уже некоторое время ковыряю TDD и задача постоянного контроля качества для меня становится всё актуальней. Особенно при пополнении команды новыми разработчиками.

Сначала я запускал тесты руками: save, switch, $ nosetests. Потом к тестам добавились проверялки качества кода и пришлось всё засунуть в скрипт:
pyflakes *.py
pep8 *.py
pylint *.py
nosetests


Скрипт запускать каждый раз ужасно лениво, поэтому небольшая оболочка на inotifywait стала запускать тесты и проверки после каждого сохранения:
while true; do
inotifywait -e modify project/*.py -qq; clear
./do_tests
done


Тут я стал более-менее доволен происходящим и даже на некоторое время расслабился. Но ведь программист кроме того, что ленив ещё и горд, поэтому результаты хочется кому-нибудь показать. Чтобы вести историю происходящего (которая очень помогает когда заходит начальник начальника и спрашивает: «ну-с, чем вы занимались последний месяц?») уже есть система контроля версий. Но она показывает только, что сделано и не даёт обзора успешности каждой ревизии. Получается что код лежит, но непонятно в каком он состоянии и что где ещё надо сделать.

Кроме того довольно тяжело следить за коллегами, которые тоже могут что-то сделать и забыть прогнать тесты, в результате в репозитории лежит битый код, не прошедший code review и при очередном pull может внезапно начаться clusterfuck.

И тут очень вовремя kmmbvnr@lj выпустил скринкаст, в котором он демонстрировал интеграцию тестирования для django-проектов с сабжем Jenkins (бывш. Hudson). Посмотрел я на все эти красоты, графики и отчёты и тоже захотел чтобы всё само пело и играло. Но у него django-jenkins, как и следует из названия, встраивается в джангу и генерит отчёты используя хитрую систему. Мой проект до джанги не дорос и скорее всего не дорастёт — это достаточно тривиальное WSGI-приложение, которое правда стремительно разрастается. Пришлось поднимать всё с нуля.

Воскресенье я на это убил, но в целом всё довольно прямолинейно и теперь у меня есть симпатичные отчёты:



Что внутри?

Блог python на хабрахабре

Язык программирования Python / Полное покрытие кода

Нужно ли делать полное покрытие кода тестами — довольно-таки частая и неоднозначная тема при обсуждении юнит-тестирования. Хотя большинство разработчиков склоняются к тому, что делать его не надо, что это неэффективно и бесполезно, я придерживаюсь противоположного мнения (по-крайней мере, при разработке на Python). В данной статье я приведу пример, как делать полное покрытие кода, и опишу недостатки и преимущества полного покрытия на основе своего опыта разработки.

PyObject Pythy revised

Внешние инструменты тестирования для Django

Кому-то хватает стандартных инструментов тестирования Django, кому-то нет. Мне стандартного мало и я сделал обзор сторонних инструментов тестирования в Django.

В обзор попали:

Самое забавное, что я опросил уважаемых мною знакомых “джангонавтов”, и оказалось, что народ в большинстве своём удовлетворяется стандартными django.test.TestCase и django.test.Client

.

Django sane testing

Sane testing закрепляет стратегию тестирования “нужна БД — django.test.TestCase, можно обойтись без БД — unittest.TestCase” и делает ее более явной. Sane testing предоставляет базовые классы для тестирования в стиле xUnit в следующих вариациях:

  • если тестовая БД не требуется, то UnitTestCase
  • если требуется тестовая БД, но каждый тест можно “обернуть” транзакцией и после успешного выполнения теста эту транзакцию откатить — DatabaseTestCase (сюда же относятся и тесты, использующие django.test.Client)
  • если нужна тестовая БД и тесты используют транзакции (в этом случае, БД сбрасывается для каждого теста) — DestructiveDatabaseTestCase
  • если для тестов нужен http-сервер (например, для проверки http basic/digest аутентификации) — то HttpTestCase (он же является и деструктивным для БД)
  • для функциональных тестов при помощи Selenium RCSeleniumTestCase

Django test utils

Django-test-utils примечателен оригинальными идеям, однако реализация хромает. Первым, чем выделяются test utils — генератор функциональных тестов. Вы запускаете manage.py testmaker, запускается обычный dev-http сервер, ходите по ссылкам, а testmaker записывает ваши действия. Потом вы останавливаете dev-http сервер и вуаля — у вас есть сгенерированные тесты. Идея хороша. Для twill есть инструменты генерирования тестов, но не нативные, а использующие более общие генераторы веб-тестов. Для Selenium есть родные инструменты подготовки тестов “натыкиванием”, но сам Selenium, IMHO, не очень удобно запускать (по крайней мере, в Django-инфраструктуре). Но тесты, которые создает testmaker, мне не особо понравились: и стиль кода выпадает (например, там для отступов используется tab), и сами тесты (в содержательной части) мне не особо понравились.

Дальше больше и test utils предоставляют еще один интересный инструмент — краулер. Он считывает urlconf, потом ходит по объявленным ссылкам (с опциональной возможностью записывать время отклика) и отчитывается, на какие урлы из urlconf он ни разу не ходил. Бывает полезно ;)

На этом дело не заканчивается, и test utils еще дают небольшую интеграцию Django и twill, взятую у djutils.test. Правда, взята бездарно, потому что testmaker не умеет генерировать тесты для twill.

В целом, у меня создалось впечатление, что эти же идеи можно было реализовать намного более удачно и получить шикарный инструмент. Ну а пока, это разношерстный набор оригинальных интересных инструментов, обязательных к просмотру, а вот к использованию… по крайней мере я не решился.

Django satprep

Django satprep минималистичен: это nose test runner (взятый из basie) и небольшой полезный модуль для nose+twill, делающий преднастройку WSGI intercept. В двух словах: идея WSGI intercept в том, что для функционального тестирования используется не полноценный http-клиент и http-сервер, а как конечная цель тестирования используется WSGI приложение.

djutils.test

Djutils — эта куча всякого Django-related кода. Я не стал толком рассматривать все его фичи, а сконцентрировался на тестировании, так что рассматриваем дальше только djutils.test. Выше этот пакет уже упоминался, как оригинальное место, откуда заимствована интеграция Django и twill. Интеграция заключается в

  1. По сайту можно ходить по относительным ссылкам, так что не нужно привязываться к хосту и порту для twill
  2. Возможность использовать reverse-resolving вместе урлов
  3. Возможность для аутентификации давать экземпляр django.contrib.auth.User

Из оставшихся фич: nose test runner (своя реализация) и py.test runner.

В целом, мне djutils не приглянулся, с миру по нитке, собственный стиль кода, который мне не особо понравился, отсутствие какой-либо документации… В общем, не очень хорошее впечатление.

NoseDjango

В NoseDjango применен метод “от противного”. Большинство проектов используют возможности Django для применения кастомных test runner’ов. NoseDjango наоборот, использует расширяемость nose и реализован в виде nose-плагина. Инсталляция NoseDjango добавляет в nosetests опцию --with-django и настраивает тестовое окружения Django перед запуском тестов. В принципе, работает как заявлено, но мне пока что больше нравится запускать джанговские тесты при помощи python manage.py test, хотя может и этот плагин распробую…

tddspry

Подход tddspry напоминает подход Django sane testing — явно разделенные базовые классы тестов:

  • NoseTestCase — полная аналогия unittest.TestCase, не использует БД
  • DatabaseTestCase — тесты, которым нужны БД
  • HttpTestCase — twill-тесты, также есть кое-какие хелперы.

В общем и целом, создалось впечатление “почти django sane testing с twill вместо selenium”.

Что я выбрал и почему

Когда я начинал делать обзор, я искал инструмент, который позволил бы мне:

  1. Использовать уже написанные тесты, которые на момент анализа запускались python manage.py test
  2. Писать некоторые тесты в nose-стиле (т.е. assert’ами, а не используя xUnit API). Это не потому, что мне не нравится xUnit API, а потому что кое-какие тесты проще писать и поддерживать именно в nose-стиле.
  3. Первые два пункта были критическими, а этот пункт опциональным: по возможности дать привязки к twill (меня больше интересовал вопрос автоматического обхода набора twill-тестов, чем Django-интеграция и улучшенный API для twill’а).

Так вот, ни один из просмотренных инструментов не подходил под требования пункта 1. Т.е. стандартный джанговский test runner нормально запускал тесты, я переключался на альтернативный test runner, и тот не видел половину тестов.

Немного проясню причины. Дело в том, что стандартный django.test.simple.run_tests обходит все установленные приложения и ищет тесты в оговоренных местах: в модуле моделей и в модуле/пакете <app>.tests. Все рассмотренные здесь инструменты используют поиск тестов средствами nose. Таким образом, если у вас есть проект и подключены приложения вне дерева кода этого проекта, то джанговский test runner их запускает, а nose test discovering их не находит.

Поэтому я взял наиболее простой django-satprep и адаптировал его под мои требования. Пункт 2 выполнился автоматически, а в качестве бонуса nose ловит тесты в тест-пакете, которые и не перечислены в __init__.py внутри <app>.tests. По правде сказать, адаптация не даёт мне чувства законченности и у нее есть неизящные решения, наследованные от satprep (например, опции для nose передаются в виде python manage.py test -- -vds), но она удовлетворяет текущим требованиям, а дальше будет видно, то ли переключаться на NoseDjango, то ли дальше “дотачивать” свой форк satprep.

А про twill подробнее я расскажу в другой раз ;)

Метки

.net .NET C# .sort 1.2 2009 2010 404 error admin ajax amazon analytics and apache api archlinux asp.net async asynchronous autocomplete bash blender blog blogengine blogs book bootstrap bot bpython buildout byteflow bzr C c plus plus C++ cache cbv Chaco checkio chrome ci ckeditor class based views clojure closure cms cms с удобной админкой code coding style collectd COM comet competition conference ConfigParser contest Context continuous integration CouchDB coverage CppCMS cpyext cpython crud csrf CSS ctypes curl custom model fields cx_freeze cython database db dbm dbqueries debian debug debugging decorator decorators deploy deployment descriptor design dev devconf developers development diveintopython Django django 1.2 django 1.3 django advent django framework django template django trunk django weblog django-admin-tools django-cms django-compressor django-hosts django-piston django-registration django-sphinx django.admin djangoadvent djangocms djangodash doc documentation drupal e-legion eclipse EGit emacs encoding Enthought epoll erlang event exception ExtJS fabric facebook fastcgi finaloption fixtures fonts forms formset fp framework freebsd freeswitch fs2web ftp fun funcparserlib functional gae gamin gandi generic views gettext gevent gil git github gitosis Google Google App Engine google picasa Google Translate google wave Google Web Toolkit grab grablab greenlet gtd gui haskell hg hgshelve highlighter host hosting how-to howto html html5lib Hudson humor i18n icfpc ide idiomatic image-scripting improvements Internet interpreter ipython ironpython izmenimsya.ru jabber java javascript jenkins jetbrains JIT job jquery json jstree jython kde kiev kiyv kyivpy l10n ldap library libs Life Links linux Linux & Unix LLVM logging logs lxml Mac OS X magic mail markdown Matplotlib Mayavi maybe mediavirus meetup memcache Memcached memory messages metaclass middleware migration mikrotik mkd model models mod_python mod_wsgi mongodb monitoring mptt musicmans.ru musicx mvc my-projects mysql netCDF networkx newforms newforms-admin news nginx Nhibernate nix nose NoSQL numpy oop open source OpenID openoffice opster optimization oracle orm os pagination parsing path patterns pdf PDF-принтер PEP PEP8 performance performance optimization perl personality photo php picture-driven computing PIL pinax pingback pip plasma plone plugin plugins postgresql programming progress bar psycopg2 py2exe pybb pybbm pycamp pycharm pycon pycow pycurl pydev pygtk pylons PyNGL pypy pyqt PyQt4 pyrad pyramid PySide Python Python 2.5 python 2.7 python 3 python c api python speed python-mssql python3 pywinauto Qt Qt4 queue rabbitmq radius raw sql re redis redsolution redsolution cms regexp regular expressions release repoze.bfg RequestContext reusable apps robokassa rss ru ruby ruby-on-rails sample satchmo scalability SciPy scraping screencast search selenium self.error seo server setattr settings setuptools shell sikuli sms snippet socket.io software sorting south sphinx spider sql sqlalchemy sqlite ssh startup step-by-step subdomain subversion svn SyntaxHighlighter system tags tdd tddspry teh drama template templates templatetags test testing thinkpad threading threads tips tips and tricks tools tornadio tornado tornado server tricks tutorial tweepy twisted twitter typography uapycon Ubuntu ucsvlog uml Uncategorized unicode unit test unit testing UnitTest Unladen Swallow upload urllib urls utf-8 uwsgi validation vcs versioning video vim virtualenv Visual Studio vkontakte voip wave web web-devel web-services web-разработка webdev webfaction webkit webpy websockets webtest widget widgets Win API windows Wirbel work wrapper wsgi wxPython wxWidgets wysiwyg xapian xml xmonad xmpp xpath yandex youtube zip zomg zope [cdata[cbv]] [cdata[ci]] [cdata[class based views]] [cdata[continuous integration]] [cdata[django framework]] [cdata[django-sphinx]] [cdata[django]] [cdata[nginx]] [cdata[python]] [cdata[virtualenv]] [cdata[программирование]] автоматизация администрирование администрирование django админка алгоритмы архитектура атрибуты базы данных Без рубрики безопасность библиотеки блоге бот веб-разработка видео Визуализация данных вконтакте Все записи гвидо ван россум граббер графика графы декоратор декораторы дескриптор дескрипторы документация заметки игра жизнь идея интересное киев Клиентам книги конференция личное математика метаклассы модели модули монады морфология мысли невозможное новости о облачные вычисления обо мне Обработка данных оптимизация оптимизация кода Основная лента основы парсинг парсинг сайтов перевод песочница Питон поебень поиск правила кодирования программирование Проектирование производительность работа рабочее размышлизмы Разное разработка разработка приложений разработки регулярные выражения сайт событие события ссылки статьи тестирование тесты Тюмень убунтариум фигня философия формы форум Хабрахабр хакинг хостинг шаблоны шаблоны проектирования эксперимент Эксперименты юмор я пиарюсь Яндекс