Тестирование client-api проекта

Здесь я опишу один способ тестирования проекта который состоит из API и клиента. И то и другое является самописным и идет как один проект.

И так что же мы имеем: django, django-piston, tddspry.

С тестированием отдельно взятого API проблем как и полагается - нет. А вот с клиентом - есть. Можно конечно запускать сервер API и при тестировании клиента дергать его, но тогда не будет очищаться база данных. Так же можно для каждого теста перезапускать API-сервер и тогда не будет проблем со сбросом базы. Но оба этих метода не совсем удобны, они значительно увеличивают время прохождения тестов. А так же дергать API по сети, пусть даже это и loopback, тоже добавляет времени на выполнение.

Так как у нас для вызова методов API есть отдельная функция, было решено написать такую же функцию только которая делает прямой вызов метода без никакой сети.

Стопором в данной ситуации стало формирование request’а который нужно передавать в view. Это должен быть либо WSGIRequest либо ModPythonRequest. Я использовал WSGIRequest.

if body: # словарь POST/PUT запроса
    for key, item in body.items():
        body[key] = smart_str(item, 'utf-8') # решение первых граблей, подсмотреное в коде django

query = urllib.urlencode(body or '')
request = WSGIRequest({
    'SERVER_NAME': 'test_api',
    'SERVER_PORT': '8000',
    'REQUEST_METHOD': method,
    'CONTENT_TYPE': 'application/x-www-form-urlencoded',
    'CONTENT_LENGTH': len(query),
    'SERVER_NAME': 'localhost',
    'SERVER_PORT': 8088,
    'wsgi.input': StringIO(query), # решение вторых граблей
})

Список граблей:

  • параметры запрос это ansi срока, urllib.urlencode не умеет работать с юникодом
  • тело запроса передается внутри файлового объекта

А дальше все хорошо

Что бы получить функцию обрабатывающую url, нужно импортировать urlpatterns из urls.py и пройтись по этому массиву вызывая resolve пока не найдет обработчик.

Если вы используете django-piston и хендлеры у вас с аутентификацией, то создайте ресурс заново уже без аутентификации.

P.S.: здесь не учитывается возможность передавать файлы