¿Cómo puedo burlarme de las solicitudes y la respuesta?

Resuelto kk1957 asked hace 11 años • 20 respuestas

Estoy intentando utilizar el paquete simulado de Pythons para simular requestsel módulo de Pythons. ¿Cuáles son las llamadas básicas para que pueda trabajar en el siguiente escenario?

En mi views.py, tengo una función que realiza una variedad de llamadas a request.get() con una respuesta diferente cada vez.

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

En mi clase de prueba quiero hacer algo como esto pero no puedo entender las llamadas a métodos exactos

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

Paso 2:

llama a mi vista

Paso 3:

verificar que la respuesta contenga 'respuesta a', 'respuesta b', 'respuesta c'

¿Cómo puedo completar el Paso 1 (burlarse del módulo de solicitudes)?

kk1957 avatar Apr 02 '13 06:04 kk1957
Aceptado

Así es como puedes hacerlo (puedes ejecutar este archivo tal cual):

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

Nota importante: si su MyGreatClassclase se encuentra en un paquete diferente, por ejemplo my.great.package, debe simular my.great.package.requests.geten lugar de simplemente 'request.get'. En ese caso, su caso de prueba se vería así:

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

¡Disfrutar!

Johannes Fahrenkrug avatar Feb 13 '2015 20:02 Johannes Fahrenkrug

Intente utilizar la biblioteca de respuestas . Aquí hay un ejemplo de su documentación :

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

Proporciona una gran comodidad en lugar de configurar todas las burlas usted mismo.

También está HTTPretty ... no es específico de requestsla biblioteca, es más poderoso en algunos aspectos, aunque descubrí que no se presta tan bien para inspeccionar las solicitudes que interceptó, lo cual responseslo hace con bastante facilidad.

También está httmock .

Una nueva biblioteca que está ganando popularidad recientemente sobre la venerable requestses httpx, que agrega soporte de primera clase para asíncrono. Una biblioteca burlona para httpx es: https://github.com/lundberg/respx

Anentropic avatar May 28 '2014 14:05 Anentropic

Esto es lo que funcionó para mí:

import mock
@mock.patch('requests.get', mock.Mock(side_effect = lambda k:{'aurl': 'a response', 'burl' : 'b response'}.get(k, 'unhandled request %s'%k)))
kk1957 avatar Apr 02 '2013 21:04 kk1957