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

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

Django Framework / Замена fixtures для тестов или обзор factory-boy

Facrtory-boy — это такая замена fixtures в django, которая позволяет более гибко и удобно генерировать данные для тестов с использование различных стратегий. Можно возвращать либо сохраненные модели, либо просто модели, пока еще не сохраненные, либо просто словарь атрибутов модели, связывать фабрики между собой. Раздолье для творчества. А написана она была Mark Sandstrom и сейчас активно развивается Raphaël Barrois. Идея была позаимствована из аналогичной библиотеки factory-girl для руби.

Oduvan’s Web Blog

Методология написания тестов в Django с использованием fixtures

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

Получаем фикстуру

  1. python manage.py dumpdata > all_data.json

Рассказывать, что это означает я не буду, но то есть хорошая документация по фикстурам у самой Django .

Я «обплетал» тесты уже готового написанного проекта. В нагрузку с проектом идет дамп базы, которая, как это не удивительно, может быть не целостная. Самый часты бок — это когда записи по форенключу нет. Например у Вас есть профиль, но нет юзера или есть транзакция между не существующими счетами.

Самое обидное, что Джанго Вам не поможет решить эту проблему. И получите что-то типа
Error: Unable to serialize database:

Нагугил тикет в Django Code:
https://code.djangoproject.com/ticket/6773

К которому прилагается команда, которая показывает Вам «разбитые модели», т. е. модели не полные с неверными данными в ForeignKey .
Я ее немного приукрасил возможностью удалять их автоматом https://gist.github.com/1018947. Для реальных данных удаление автоматом — это не очень обдуманный шаг, но мне сейчас надо получить хоть какую-то фикстуру.

Подержание актуальности фикстуры

Для поддержки актуальности базы между всеми разработчиками используется django-south, мне кажется это уже давно стало стандартом Django разработки. Тот же механизм можно использовать для поддержки актуальности с фикстурами, поэтому я одну фикстуру полностью перегоняю в sqlite3 базу, которую как и фикстуру держу в репозитарии проекта и для доступа к которой использую отдельный сетингс.

Сеттингс файл для этого состоит из 3х строчек (settings_lights.py):

  1. from settings import *
  2. DATABASES['default']['ENGINE'] ='django.db.backends.sqlite3'
  3. DATABASES['default']['NAME'] = 'lights.db'

Как известно, в любую команду можно передать не стандартное имя сетингс модуля.

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

  1. python manage.py runserver 0:8001settings=settings_lights
  2. python manage.py dumpdata –setting=settings_lights > all_data.json

А поддерживать актуальность фикстуры можно через миграции, которые вы создаете после изменения структуры базы

  1. python manage.py migrate –settings=settings_lights
  2. python manage.py dumpdata –setting=settings_lights > all_data.json

Тестирование

Для тестирования я использую тот-же settings_lights.py для того, чтобы использовать sqlite3 в тестах, при этом для тестов вся база будет держаться в памяти, что существенно ускорит процесс написания тестов и тестирования их.

  1. python manage.py testsettings=settings_lights

Но я думаю как финальную проверку, после того, как вы закончили с разработкой ( доработкой ) тестов можно использовать и реальный Engine.

  1. python manage.py test

А собственно сам текст тестов может выглядить так:

  1. from django.test import TestCase
  2. from django.test.client import Client
  3. from django.contrib.auth.models import User
  4.  
  5. class SimpleTest(TestCase):
  6.     fixtures = ['all_data.json']
  7.     def setUp(self):      
  8.         self.client = Client()
  9.  
  10.     def test_details(self):
  11.         print User.objects.all()

Этот пример ничего не тестирует, а просто показывает Вам, что данные на момент запуска тестов в базе уже есть. Фикстуры можно хранить как в папке fixtures любой апы, не только тестируемой. А еще в сетингсах можно прописать:

  1. FIXTURE_DIRS = (
  2.    '/path/to/myapp/fixtures/',
  3. )

Проблема с сигналами

Про сигналы в Django вы можете почитать в документции.

Фикстура — это по сути сериализация ОРМ объектов, т. е. объект будет сохранен как json, как просто текст. А значит загрузка из фикстуры — это поочередное добавление всех объектов, а добавление объектов связано с вызовом сигналов, которые в свою очередь могу сами создавать объекты моделей или изменять существующие.

Например. У Вас есть 2 модели счета и транзакции. При добавлении транзакции — дергается сигнал, по которому изменяются балансы счетов участников этой транзакции. При подготовке фикстуры вы создали одну транзакцию между двумя счетами на сумму 100 рублей, т. е. после ее проведения на одном счету прибавится 100 рублей, а на другой вычтится. Вы сохраните полученные данные в файл фикстуры, в которой будут готовые записи со счетами и транзакциями. Во время тестирования этот файл будет загружаться и вначале загрузятся модели счетов – на одном 100, на другом -100. После загрузятся транзакции и дернут сигнал, который еще раз изменит балансы на счетах и мы во время тестирования увидим состояния на счетах 200 и -200.

Решение у джанги есть , но почему-то не документированное, и как по мне — очень не удачное.

В обработчик сигнала передается параметр raw который True во время загрузки фиксутры.

Так что, если вы не хотите, чтоб обработчик сигнала работал в момент загрузки фикстуры, то первые 3 строчки вашего обработчика могут выглядит так:

  1. def trans_save(sender, instance, raw,  **kwargs):                                                                                                                                  
  2.     if raw:                
  3.         return

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

У меня все. Я описал то, как с фикстурами работаю я, и очевидно, что они могут сэкономить очень много времени Вам при разработке тестов, а также могут помогать Вам делать более качественные и реальные тесты.

Хотелось бы в комментариях увидеть критику такого подхода, дополнения, подводные камни, с которым вы сталкиваетесь. Буду дополнять статью Вашими цитатами и идеями.

Спасибо, и удачных Вам выходных.

PYонер

Snapshot опыта


  1. использовать django fixtures в формате yaml одно удовольствие, можно вставить свой тег, который вернёт определённый результат. Например:
    ### Image

    -
    model: shop.image
    pk: 1
    fields:
    src: static/shop/test/product/borsh.jpg
    description: Наваристый супец!
    content_type: !!python/object/apply:resty.utils.content_type_pk [shop, product]
    object_id: 1

    нужно передать первичный ключ объекта ContentType для модели Product, для этого применяем свой тег (
    content_type: !!python/object/apply:resty.utils.content_type_pk [shop, product]
    ), который вызывает простую функцию:
    def content_type_pk(app_label, model):
    return ContentType.objects.get(app_label=app_label, model=model).pk
    попробуйте сделать такое в json или xml не получится =)
  2. IE7 (ужасный и бессмертный для некоторых юзеров) коверкает форму и посылает данные в формате multipart/form-data хотя по умолчанию должны придти данные в формате application/x-www-form-urlencoded для фикса данного бага написал javascript код, который прописывает атрибут enctype="application/x-www-form-urlencoded" в каждую форму, где нет данного атрибута.
  3. Postgresql при сортировке значение null (None) ставит выше чем числовое значение, а Sqlite приравнивает значение null к нулю. Поэтому приходится исключать строки с полями значения которых равны null  в выборке данных, по которым будет происходить сортировка.
  4. Используйте lesscss для упрощения и облегчения своего труда при верстке страниц! По синтаксису lesscss понравился больше, чем sass\scss.

Метки

.net .NET C# 1.2 2009 2010 404 error admin ajax amazon and apache api archlinux asp.net async asynchronous autocomplete bash blender blog blogengine blogs book bootstrap bot bpython buildout byteflow bzr C C++ cache cbv Chaco checkio chrome ci ckeditor class based views clojure closure cms cms с удобной админкой code coding style COM comet competition conference ConfigParser contest Context continuous integration CouchDB coverage CppCMS cpyext cpython csrf CSS curl custom model fields 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 Translate google wave Google Web Toolkit grab greenlet gtd gui haskell hg hgshelve highlighter hosting how-to howto html html5lib Hudson humor i18n icfpc ide idiomatic image-scripting improvements Internet 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 lxml Mac OS X magic mail markdown Matplotlib Mayavi maybe mediavirus meetup memcache memory messages metaclass middleware migration mkd model models mod_wsgi mongodb monitoring mptt musicmans.ru musicx 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 pdf PDF-принтер PEP PEP8 performance perl personality php picture-driven computing PIL pinax pingback pip plasma plone plugin plugins postgresql programming psycopg2 py2exe pybb pybbm pycamp pycharm pycon pycow pycurl pydev pygtk pylons PyNGL pypy PyQt4 pyrad pyramid PySide Python Python 2.5 python 2.7 python 3 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 sql sqlalchemy sqlite ssh startup 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 UnitTest Unladen Swallow upload urllib urls utf-8 uwsgi validation vcs versioning video vim virtualenv Visual Studio voip wave web web-devel web-services web-разработка webdev webkit webpy webtest widget widgets Win API windows Wirbel work wrapper wsgi wxPython wxWidgets wysiwyg xapian xml xmonad xmpp xpath yandex youtube zip zomg zope автоматизация администрирование администрирование django админка алгоритмы архитектура базы данных Без рубрики безопасность библиотеки блоге бот видео Визуализация данных вконтакте Все записи гвидо ван россум граббер графика графы декоратор дескриптор дескрипторы документация заметки идея интересное киев Клиентам книги конференция личное математика метаклассы модели модули морфология мысли невозможное новости о облачные вычисления обо мне Обработка данных оптимизация Основная лента парсинг перевод Питон поебень поиск правила кодирования программирование Проектирование производительность работа рабочее размышлизмы Разное разработка приложений разработки регулярные выражения сайт событие события ссылки статьи тестирование тесты Тюмень фигня философия формы форум Хабрахабр хакинг шаблоны шаблоны проектирования эксперимент Эксперименты юмор Яндекс