379 Stimmen

Wie kann ich Anfragen und die Antwort nachahmen?

Ich versuche, das Mockpaket von Python zu verwenden, um das Python requests Modul zu mocken. Was sind die grundlegenden Aufrufe, um mich in untenstehendem Szenario zum Laufen zu bringen?

In meiner views.py habe ich eine Funktion, die verschiedene requests.get() Aufrufe mit jeweils einer anderen Antwort macht

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

In meiner Testklasse möchte ich etwas Ähnliches tun, kann jedoch die genauen Methodenaufrufe nicht herausfinden

Schritt 1:

# Das requests Modul mocken
# Wenn mockedRequests.get('aurl') aufgerufen wird, dann 'a response' zurückgeben
# Wenn mockedRequests.get('burl') aufgerufen wird, dann 'b response' zurückgeben
# Wenn mockedRequests.get('curl') aufgerufen wird, dann 'c response' zurückgeben

Schritt 2:

Meine Ansicht aufrufen

Schritt 3:

Überprüfen, ob die Antwort 'a response', 'b response', 'c response' enthält

Wie kann ich Schritt 1 (Mocken des requests Moduls) abschließen?

447voto

Johannes Fahrenkrug Punkte 40264

So können Sie es machen (Sie können diese Datei wie sie ist ausführen) :

import requests
import unittest
from unittest import mock

# Dies ist die Klasse, die wir testen möchten
class MyGreatClass:
    def fetch_json(self, url):
        response = requests.get(url)
        return response.json()

# Diese Methode wird vom Mock verwendet, um requests.get zu ersetzen
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)

# Unsere Testfall-Klasse
class MyGreatClassTestCase(unittest.TestCase):

    # Wir patchen 'requests.get' mit unserer eigenen Methode. Das Mock-Objekt wird an unsere Testfall-Methode übergeben.
    @mock.patch('requests.get', side_effect=mocked_requests_get)
    def test_fetch(self, mock_get):
        # Assert-Anrufe von requests.get
        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)

        # Wir können sogar überprüfen, ob unsere Mock-Methode mit den richtigen Parametern aufgerufen wurde
        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()

Wichtiger Hinweis: Wenn Ihre MyGreatClass-Klasse in einem anderen Paket lebt, sagen wir in my.great.package, müssen Sie my.great.package.requests.get statt nur 'requests.get' mocken. In diesem Fall würde Ihr Testfall so aussehen:

import unittest
from unittest import mock
from my.great.package import MyGreatClass

# Diese Methode wird vom Mock verwendet, um requests.get zu ersetzen
def mocked_requests_get(*args, **kwargs):
    # Wie oben

class MyGreatClassTestCase(unittest.TestCase):

    # Jetzt müssen wir 'my.great.package.requests.get' patchen
    @mock.patch('my.great.package.requests.get', side_effect=mocked_requests_get)
    def test_fetch(self, mock_get):
        # Wie oben

if __name__ == '__main__':
    unittest.main()

Viel Spaß!

263voto

Anentropic Punkte 28341

Versuchen Sie die Antworten-Bibliothek. Hier ist ein Beispiel aus ihrer Dokumentation:

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

Es bietet eine ziemlich praktische Möglichkeit, anstatt alles selbst zu fälschen.

Es gibt auch HTTPretty... es ist nicht spezifisch für die requests-Bibliothek, aber in mancher Hinsicht leistungsfähiger, obwohl es sich meiner Erfahrung nach nicht so gut zum Inspektionieren der abgefangenen Anfragen eignet, was mit responses recht einfach möglich ist

Es gibt auch httmock.

Eine neue Bibliothek, die in letzter Zeit an Popularität gewinnt, ist neben der angesehenen requests-Bibliothek httpx, die eine erstklassige Unterstützung für asynchrones Arbeiten bietet. Eine Mocking-Bibliothek für httpx ist: https://github.com/lundberg/respx

77voto

kk1957 Punkte 7506

Hier ist, was für mich funktioniert hat:

import mock
@mock.patch('requests.get', mock.Mock(side_effect = lambda k:{'aurl': 'a response', 'burl' : 'b response'}.get(k, 'unbehandelte Anfrage %s'%k)))

51voto

AnaPana Punkte 1838

Ich habe requests-mock verwendet, um Tests für ein separates Modul zu schreiben:

# module.py
import requests

class A():

    def get_response(self, url):
        response = requests.get(url)
        return response.text

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

35voto

tingyiy Punkte 639

So mocken Sie requests.post und ändern Sie es in Ihre HTTP-Methode um

@patch.object(requests, 'post')
def Ihre_Testmethode(self, mockpost):
    mockantwort = Mock()
    mockpost.return_value = mockantwort
    mockantwort.text = 'Mock-Rückkehr'

    #Rufen Sie jetzt Ihre Zielmethode auf

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X