Мое приложение python делает много HTTP-запросов ко многим URL-адресам, используя urllib2. Я хотел бы построить набор unit test для проверки моего синтаксического анализа и обработки ошибок.
У меня есть каталог, полный тестовых данных, с несколькими файлами, каждый файл, содержащий один ответ HTTP, с заголовками и данными ответа. (с использованием curl -i) В некоторых случаях эти файлы содержат сообщения об ошибках HTTP (необходимые для проверки обработки ошибок)
В идеале я хотел бы создать mock-объект для замены urllib2.urlopen и вернуть объект mock response.
Мне интересно, есть ли простой способ заставить urllib2 загружать HTTP-ответ непосредственно из файла и анализировать эти данные urllib2 для создания соответствующего объекта ответа (как если бы ответ был прочитан с URL-адреса.
Я попытался использовать url, построенный с помощью протокола "file://", однако заголовки ответов HTTP в верхней части файла не были прочитаны и не были правильно проанализированы.
В качестве альтернативы я рассматриваю возможность написания небольшого класса веб-сервера для работы с тестовыми файлами, однако это похоже на немного больше работы, чем хотелось бы. Было бы проще, если бы urllib2 каким-то образом восстановил объект ответа из ответов http, которые я уже сохранил в файлах (без необходимости создавать веб-сервер для их повторного использования)
Любые идеи?
Я думаю, что лучший подход состоит в том, чтобы высмеять подмножество httplib.HTTPConnection
(вызовите полученный класс mockcon
для конкретности в следующем) и добавьте обработчик, использующий его и подклассифицируя HTTPHandler
(использовать в build_opener
- - подклассификация означает, что он может заменить HTTPHandler
, который используется build_opener
по умолчанию):
class MockHTTPHandler(urllib2.HTTPHandler):
def http_open(self, req):
return self.do_open(mockcon, req)
Класс mockcon должен предоставлять методы do_open
call - несколько могут быть манекенами (т.е. принимать и игнорировать произвольные args и kwds и ничего не делать):
set_debuglevel
_set_tunnel
request
(может интересоваться 2-м аргументом request
, поскольку он дает "селекторную" часть URL-адреса).
Метод __init__
mockcon
получает хост-часть URL-адреса в качестве первого arg (то есть сначала после self
, конечно) и должен игнорировать следующие kwds (используемые для установки тайм-аута).
Метод get_response
mockcon
(без аргументов, за пределами, конечно, self
) должен возвращать объект ответа HTTP - то есть файл-подобный читаемый объект, который также имеет атрибуты .msg
, .status
, и .reason
и метод get_full_url()
, чтобы вернуть URL.
Вы можете использовать фактический экземпляр httplib.HTTPResponse
для последней роли, но вы должны инициализировать его с помощью одного mock/dummy arg, который имеет аргумент makefile
(игнорирует его аргументы и kwds и возвращает все), и сразу после инициализируя его, reset его аргумент .fp
должен быть открытым файлом rb
, дающим точно байты, которые настоящий HTTP-ответ получит в своем сокете.
Я думаю, что создание полноценного макета для всего вызова urllib2.urlopen
может быть проще, чем эта попытка повторного использования большинства функций urllib2
(и httplib
, которые он использует внутри), хотя, возможно, и не совсем так же просто, как подход "локального веб-сервера", который, по вашему мнению, больше подходит для работы. Но стоит подумать обо всех трех подходах (макет, безусловно, будет самым легким/быстрым в работе, самый медленный локальный веб-сервер... а также потребует как-то модификации URL-адресов, предварительно назначив им http://localhost:someport/
),.
Серверный подход определенно не работает, это, вероятно, самая легкая и наименее работающая из всех ваших альтернатив.
Отъезд: http://docs.python.org/library/simplehttpserver.html
7-строчная программа python, которая при запуске из определенного каталога будет обслуживать все файлы (и, рекурсивно, любые файлы в подкаталогах) через HTTP.
Вероятно, вы можете запустить свой unit test код и остановить сервер, поэтому вам не нужно его запускать, даже если он не тестируется.