How can I mock requests and reply?

I am trying to use the Pythons package to prototype the Pythons requests module. What are the basic requirements to get me to work in the script below?

In my views.py, I have a function that makes different requests.get () requests with different responses every time

 def myview(request): res1 = requests.get('aurl') res2 = request.get('burl') res3 = request.get('curl') 

In my test class, I want to do something similar, but I cannot understand the exact method calls

Step 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' 

Step 2:

Call my mind

Step 3:

check the answer contains "answer", "answer b", "answer c"

How can I follow Step 1 (mock the query module)?

+144
python mocking request
Apr 01 '13 at
source share
9 answers

Here is what worked for me:

 import mock @mock.patch('requests.get', mock.Mock(side_effect = lambda k:{'aurl': 'a response', 'burl' : 'b response'}.get(k, 'unhandled request %s'%k))) 
+35
Apr 2
source share

Here is how you can do it (you can run this file as is):

 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() 

Important Note: If your MyGreatClass class lives in a different package, say my.great.package , you need to make fun of my.great.package.requests.get instead of "request.get". In this case, your test case will look like this:

 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() 

Enjoy it!

+187
Feb 13 '15 at 20:00
source share

Try using the answer library :

 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"}' 

provides pretty nice convenience compared to setting all the taunts

There is also HTTPretty :

This does not apply to the requests library, which are more powerful in some way, although I found that it does not lend itself to inspecting requests that it intercepted so well that making responses quite easily

There is also httmock .

+82
May 28 '14 at 14:29
source share

I used requests-mock to write tests for a separate module:

 # module.py import requests class A(): def get_response(self, url): response = requests.get(url) return response.text 

And tests:

 # 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() 
+23
May 08 '15 at 20:43
source share

this is how you cheat request.post, change it to your http method

 @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 
+12
Feb 17 '17 at 23:02
source share

If you want to make fun of a fake answer, another way to do this is to simply instantiate the HttpResponse base class, for example:

 from django.http.response import HttpResponseBase self.fake_response = HttpResponseBase() 
+2
Mar 31 '16 at 18:37
source share

One of the possible ways to bypass requests is to use the betamax library, it records all requests, and after that, if you make a request in the same URL with the same parameters, then betamax will use the recorded request, I used it to test the web scanner and this save me a lot of time.

 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/

+1
Sep 12 '18 at 17:43
source share

Just useful advice for those who are still having difficulty: when converting from urllib or urllib2 / urllib3 to requests and when trying to simulate response, I received a slightly confusing error when implementing my layout:

with requests.get(path, auth=HTTPBasicAuth('user', 'pass'), verify=False) as url:

AttributeError: __enter__

Well, of course, if I knew anything about how with works (I didn't know), I would know that this is a rudimentary, unnecessary context (from PEP 343 ). There is no need to use the query library because it does the same for you under the hood . Just remove with and use naked requests.get(...) and Bob is your uncle .

0
Dec 27 '18 at 22:31
source share

Can someone help me solve the problem below

Python HTTP Post method returns a response as a magicmock instead of a value

@ max-p-mageehttps @Ronald Theodoro

0
Jun 07 '19 at 9:39 on
source share



All Articles