Я пытаюсь использовать пакет Pythons для макетирования модуля requests
Pythons. Каковы основные требования, чтобы заставить меня работать в сценарии ниже?
В моем views.py у меня есть функция, которая каждый раз делает разные запросы request.get() с разным откликом
def myview(request):
res1 = requests.get('aurl')
res2 = request.get('burl')
res3 = request.get('curl')
В моем тестовом классе я хочу сделать что-то подобное, но не могу понять точные вызовы методов
Шаг 1:
# Mock the requests module
# when mockedRequests.get('aurl') is called then return 'a response'
# when mockedRequests.get('burl') is called then return 'b response'
# when mockedRequests.get('curl') is called then return 'c response'
Шаг 2:
Позвони мой взгляд
Шаг 3:
проверить ответ содержит "ответ", "ответ b", "ответ c"
Как я могу выполнить Шаг 1 (издеваться над модулем запросов)?
Ответ 1
Вот что сработало для меня:
import mock
@mock.patch('requests.get', mock.Mock(side_effect = lambda k:{'aurl': 'a response', 'burl' : 'b response'}.get(k, 'unhandled request %s'%k)))
Ответ 2
Вот как вы можете это сделать (вы можете запустить этот файл как есть):
import requests
import unittest
from unittest import mock
# This is the class we want to test
class MyGreatClass:
def fetch_json(self, url):
response = requests.get(url)
return response.json()
# This method will be used by the mock to replace requests.get
def mocked_requests_get(*args, **kwargs):
class MockResponse:
def __init__(self, json_data, status_code):
self.json_data = json_data
self.status_code = status_code
def json(self):
return self.json_data
if args[0] == 'http://someurl.com/test.json':
return MockResponse({"key1": "value1"}, 200)
elif args[0] == 'http://someotherurl.com/anothertest.json':
return MockResponse({"key2": "value2"}, 200)
return MockResponse(None, 404)
# Our test case class
class MyGreatClassTestCase(unittest.TestCase):
# We patch 'requests.get' with our own method. The mock object is passed in to our test case method.
@mock.patch('requests.get', side_effect=mocked_requests_get)
def test_fetch(self, mock_get):
# Assert requests.get calls
mgc = MyGreatClass()
json_data = mgc.fetch_json('http://someurl.com/test.json')
self.assertEqual(json_data, {"key1": "value1"})
json_data = mgc.fetch_json('http://someotherurl.com/anothertest.json')
self.assertEqual(json_data, {"key2": "value2"})
json_data = mgc.fetch_json('http://nonexistenturl.com/cantfindme.json')
self.assertIsNone(json_data)
# We can even assert that our mocked method was called with the right parameters
self.assertIn(mock.call('http://someurl.com/test.json'), mock_get.call_args_list)
self.assertIn(mock.call('http://someotherurl.com/anothertest.json'), mock_get.call_args_list)
self.assertEqual(len(mock_get.call_args_list), 3)
if __name__ == '__main__':
unittest.main()
Важное примечание: Если ваш класс MyGreatClass
живет в другом пакете, скажем my.great.package
, вам нужно высмеять my.great.package.requests.get
вместо "request.get". В этом случае ваш тестовый пример будет выглядеть следующим образом:
import unittest
from unittest import mock
from my.great.package import MyGreatClass
# This method will be used by the mock to replace requests.get
def mocked_requests_get(*args, **kwargs):
# Same as above
class MyGreatClassTestCase(unittest.TestCase):
# Now we must patch 'my.great.package.requests.get'
@mock.patch('my.great.package.requests.get', side_effect=mocked_requests_get)
def test_fetch(self, mock_get):
# Same as above
if __name__ == '__main__':
unittest.main()
Наслаждайтесь!
Ответ 3
Попробуйте использовать библиотеку ответов:
import responses
import requests
@responses.activate
def test_simple():
responses.add(responses.GET, 'http://twitter.com/api/1/foobar',
json={'error': 'not found'}, status=404)
resp = requests.get('http://twitter.com/api/1/foobar')
assert resp.json() == {"error": "not found"}
assert len(responses.calls) == 1
assert responses.calls[0].request.url == 'http://twitter.com/api/1/foobar'
assert responses.calls[0].response.text == '{"error": "not found"}'
обеспечивает довольно приятное удобство по сравнению с настройкой всех насмешек
Там также HTTPretty:
Это не относится к requests
библиотеке, более мощные в некотором роде, хотя я нашел, что это не поддается так хорошо осматривали запросы, которые он перехваченные, что responses
делает довольно легко
Там тоже httmock.
Ответ 4
Я использовал requests-mock для написания тестов для отдельного модуля:
# module.py
import requests
class A():
def get_response(self, url):
response = requests.get(url)
return response.text
И тесты:
# tests.py
import requests_mock
import unittest
from module import A
class TestAPI(unittest.TestCase):
@requests_mock.mock()
def test_get_response(self, m):
a = A()
m.get('http://aurl.com', text='a response')
self.assertEqual(a.get_response('http://aurl.com'), 'a response')
m.get('http://burl.com', text='b response')
self.assertEqual(a.get_response('http://burl.com'), 'b response')
m.get('http://curl.com', text='c response')
self.assertEqual(a.get_response('http://curl.com'), 'c response')
if __name__ == '__main__':
unittest.main()
Ответ 5
вот как вы обманываете request.post, меняете его на свой http-метод
@patch.object(requests, 'post')
def your_test_method(self, mockpost):
mockresponse = Mock()
mockpost.return_value = mockresponse
mockresponse.text = 'mock return'
#call your target method now
Ответ 6
Если вы хотите высмеять фальшивый ответ, другой способ сделать это - просто создать экземпляр базового класса HttpResponse, например:
from django.http.response import HttpResponseBase
self.fake_response = HttpResponseBase()
Ответ 7
Один из возможных способов обойти запросы - использовать библиотеку betamax, она записывает все запросы, и после этого, если вы делаете запрос в том же URL с теми же параметрами, то betamax будет использовать записанный запрос, я использовал его для тестирования веб-сканера и это сэкономит мне много времени.
import os
import requests
from betamax import Betamax
from betamax_serializers import pretty_json
WORKERS_DIR = os.path.dirname(os.path.abspath(__file__))
CASSETTES_DIR = os.path.join(WORKERS_DIR, u'resources', u'cassettes')
MATCH_REQUESTS_ON = [u'method', u'uri', u'path', u'query']
Betamax.register_serializer(pretty_json.PrettyJSONSerializer)
with Betamax.configure() as config:
config.cassette_library_dir = CASSETTES_DIR
config.default_cassette_options[u'serialize_with'] = u'prettyjson'
config.default_cassette_options[u'match_requests_on'] = MATCH_REQUESTS_ON
config.default_cassette_options[u'preserve_exact_body_bytes'] = True
class WorkerCertidaoTRT2:
session = requests.session()
def make_request(self, input_json):
with Betamax(self.session) as vcr:
vcr.use_cassette(u'google')
response = session.get('http://www.google.com')
https://betamax.readthedocs.io/en/latest/
Ответ 8
Просто полезный совет для тех, кто все еще испытывает трудности: при конвертации из urllib или urllib2/urllib3 в запросы и при попытке смоделировать response- я получал слегка запутывающую ошибку при реализации моего макета:
with requests.get(path, auth=HTTPBasicAuth('user', 'pass'), verify=False) as url:
AttributeError: __enter__
Ну, конечно, если бы я знал что-либо о том, как with
работами (я не знал), я бы знал, что это рудиментарный, ненужный контекст (из PEP 343). Нет необходимости при использовании библиотеки запросов, потому что она делает то же самое для вас под капотом. Просто удалите with
и используйте голые requests.get(...)
и Боб ваш дядя.
Ответ 9
Может кто-нибудь помочь мне решить проблему ниже
Метод Python HTTP Post возвращает ответ в виде объекта magicmock вместо значения
@max-p-mageehttps @Ronald Theodoro