J'essaie d'utiliser le paquet fictif Pythons pour ficher le module requests
Pythons Quels sont les appels de base pour me faire travailler dans le scénario ci-dessous?
Dans mon views.py, j'ai une fonction qui fait une variété d'appels requests.get () avec une réponse différente à chaque fois
def myview(request):
res1 = requests.get('aurl')
res2 = request.get('burl')
res3 = request.get('curl')
Dans ma classe de test, je veux faire quelque chose comme ceci mais je ne peux pas comprendre les appels de méthode exacts
Étape 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'
Étape 2:
Appelle ma vue
Étape 3:
vérifier que la réponse contient 'une réponse', 'réponse b', 'réponse c'
Comment puis-je terminer l'étape 1 (mocker le module de demandes)?
Voici ce qui a fonctionné pour moi:
import mock
@mock.patch('requests.get', mock.Mock(side_effect = lambda k:{'aurl': 'a response', 'burl' : 'b response'}.get(k, 'unhandled request %s'%k)))
Voici comment vous pouvez le faire (vous pouvez exécuter ce fichier tel quel):
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 __== '__main__':
unittest.main()
Remarque importante: Si votre classe MyGreatClass
réside dans un package différent, par exemple my.great.package
, vous devez simuler my.great.package.requests.get
au lieu de simplement 'request.get'. Dans ce cas, votre cas de test ressemblerait à ceci:
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 __== '__main__':
unittest.main()
Prendre plaisir!
Essayez d’utiliser la bibliothèque de réponses :
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"}'
fournit tout à fait une bonne commodité sur la mise en place de tout le moqueur
Il y a aussi HTTPretty :
ce n'est pas spécifique à la bibliothèque requests
, plus puissante à certains égards bien que j'ai constaté qu'elle ne se prêtait pas si bien à l'inspection des requêtes interceptées, ce que responses
fait assez facilement
et httmock :
J'ai utilisé request-mock pour écrire des tests pour un module distinct:
# module.py
import requests
class A():
def get_response(self, url):
response = requests.get(url)
return response.text
Et les 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 __== '__main__':
unittest.main()
voici comment vous vous moquez de requests.post, changez-le en votre méthode 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
Si vous voulez simuler une fausse réponse, vous pouvez également instancier une instance de la classe de base HttpResponse, comme ceci:
from Django.http.response import HttpResponseBase
self.fake_response = HttpResponseBase()
Une solution possible pour contourner les requêtes consiste à utiliser la bibliothèque betamax. Elle enregistre toutes les requêtes. Par la suite, si vous faites une requête dans la même URL avec les mêmes paramètres, le betamax utilisera la requête enregistrée. Je l'ai utilisé pour tester le crawler Web. et cela m'a fait gagner beaucoup de temps.
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')