Чистые Mocking удаленные серверы и API для Django Unittests

У меня есть тернистая проблема, с которой я не могу справиться. В настоящее время я пишу модульные тесты для пользовательского auth-backend django. В нашей системе мы фактически имеем два backend: один встроенный django backend и пользовательский бэкэнд, который отправляет запросы API на Java, который возвращает информацию о пользователе в форме XML. Теперь я пишу модульные тесты, поэтому я не хочу отправлять запросы за пределами системы, как это, я не пытаюсь проверить API Java, поэтому мой вопрос в том, как я могу обойти это и высмеять побочные эффекты самым надежным способом.

Функция, которую я тестирую, примерно такая, где значение параметра url – это только базовый url для Java-сервера, который аутентифицирует данные имени пользователя и пароля и возвращает xml, а значение сервиса – всего лишь магия для построения запроса url, его несущественное для нас:

@staticmethod def get_info_from_api_with_un_pw(username, password, service=12345): url = settings.AUTHENTICATE_URL_VIA_PASSWORD if AUTH_FIELD == "username": params = {"nick": username, "password": password} elif AUTH_FIELD == "email": params = {"email": username, "password": password} params["service"] = service encoded_params = urlencode([(k, smart_str(v, "latin1")) for k, v in params.items()]) try: # get the user's data from the api xml = urlopen(url + encoded_params).read() userinfo = dict((e.tag, smart_unicode(e.text, strings_only=True)) for e in ET.fromstring(xml).getchildren()) if "nil" in userinfo: return userinfo else: return None 

Итак, мы получаем xml, анализируем его в dict и, если присутствует ключевой ниль, мы можем вернуть dict и продолжить счастливую и аутентифицированную. Ясно, что одним из решений является просто найти способ как-то переопределить или обезвредить логику в переменной xml, я нашел этот ответ:

Как можно mock / stub python module как urllib

Я попытался реализовать что-то подобное, но детали там очень отрывочны, и я не мог заставить их работать.

Я также захватил ответ xml и поместил его в локальный файл в тестовую папку с намерением найти способ использовать это как макетный ответ, который передается в параметр url тестовой функции, что-то вроде этого переопределит URL-адрес :

 @override_settings(AUTHENTICATE_URL_VIA_PASSWORD=(os.path.join(os.path.dirname(__file__), "{0}".format("response.xml")))) def test_get_user_info_username(self): self.backend = RemoteAuthBackend() self.backend.get_info_from_api_with_un_pw("user", "pass") 

Но это также должно учитывать логику построения URL, которую определяет функция (например, «url + encoded_params»). Опять же, я мог бы переименовать файл ответов так же, как конкатенированный URL-адрес, но это становится менее похожим на хороший модульный тест для функции и больше «читов», все это просто становится все более и более хрупким. с этими решениями, и на самом деле это всего лишь арматура в любом случае, чего я также хочу избежать, если это вообще возможно.

Я также задавался вопросом, может ли быть способ обслуживать xml на сервере разработки django, а затем указывать на него функцию? Это похоже на более здравое решение, но многие поисковые запросы не дали мне никаких подсказок, если бы такое было возможно или целесообразно, и даже тогда я не думаю, что это было бы испытание на запуск за пределами среды разработки.

Поэтому, в идеале, мне нужно уметь каким-то образом издеваться над «сервером», чтобы заменить Java API в вызове функции, или каким-то образом обслуживать некоторую полезную нагрузку xml, которую функция может открывать как свой url, или monkeypatch функция из сам тест или …

Есть ли у библиотеки макетов соответствующие инструменты для выполнения таких задач?

http://www.voidspace.org.uk/python/mock

Итак, в этом вопросе есть два момента. 1) Я хотел бы решить мою конкретную проблему чистым способом и, что более важно, 2) каковы наилучшие методы для чистого написания модульных тестов Django, когда вы зависите от данных, файлов cookie, и т. д. для аутентификации пользователей из удаленного API, который находится за пределами вашего домена?

2 Solutions collect form web for “Чистые Mocking удаленные серверы и API для Django Unittests”

Библиотека-макет должна работать при правильном использовании. Я предпочитаю библиотеку minimock, и я написал небольшую тестовую таблицу базового блока ( minimocktest ), которая помогает в этом.

Если вы хотите интегрировать этот тестовый тест с Django для тестирования urllib вы можете сделать это следующим образом:

 from minimocktest import MockTestCase from django.test import TestCase from django.test.client import Client class DjangoTestCase(TestCase, MockTestCase): ''' A TestCase class that combines minimocktest and django.test.TestCase ''' def _pre_setup(self): MockTestCase.setUp(self) TestCase._pre_setup(self) # optional: shortcut client handle for quick testing self.client = Client() def _post_teardown(self): TestCase._post_teardown(self) MockTestCase.tearDown(self) 

Теперь вы можете использовать этот тестовый тест вместо непосредственного использования тестового примера Django:

 class MySimpleTestCase(DjangoTestCase): def setUp(self): self.file = StringIO.StringIO('MiniMockTest') self.file.close = self.Mock('file_close_function') def test_urldump_dumpsContentProperly(self): self.mock('urllib2.urlopen', returns=self.file) self.assertEquals(urldump('http://pykler.github.com'), 'MiniMockTest') self.assertSameTrace('\n'.join([ "Called urllib2.urlopen('http://pykler.github.com')", "Called file_close_function()", ])) urllib2.urlopen('anything') self.mock('urllib2.urlopen', returns=self.file, tracker=None) urllib2.urlopen('this is not tracked') self.assertTrace("Called urllib2.urlopen('anything')") self.assertTrace("Called urllib2.urlopen('this is mocked but not tracked')", includes=False) self.assertSameTrace('\n'.join([ "Called urllib2.urlopen('http://pykler.github.com')", "Called file_close_function()", "Called urllib2.urlopen('anything')", ])) 

Вот основа решения, которое я закончил для записи. В конце концов я использовал библиотеку Mock, а не Mockito, но идея такая же:

 from mock import patch @override_settings(AUTHENTICATE_LOGIN_FIELD="username") @patch("mymodule.auth_backend.urlopen") def test_get_user_info_username(self, urlopen_override): response = "file://" + os.path.join(os.path.dirname(__file__), "{0}".format("response.xml")) # mock patch replaces API call urlopen_override.return_value = urlopen(response) # call the patched object userinfo = RemoteAuthBackend.get_info_from_api_with_un_pw("user", "pass") assert_equal(type(userinfo), dict) assert_equal(userinfo["nick"], "user") assert_equal(userinfo["pass"], "pass") 
  • Как один модуль тестирует условия ошибки для API Python / C, таких как PyType_Ready и PyObject_New?
  • В Python, какой хороший шаблон для отключения определенного кода во время модульных тестов?
  • Есть ли способ начать модульные тесты, связанные только с измененным кодом?
  • Как очистить / недействить кеш NDB в тестах
  • Отметьте HTTP-запрос, который истекает с помощью HTTPretty
  • Тесты преуспевают, все еще получают трассировку
  • Unittest вызывает sys.exit ()
  • Python 2.7 Единичный тест: предупреждение о предупреждении буфера
  • Python - лучший язык программирования в мире.