Ich habe mit Johannes Farhenkrugs Antwort hier angefangen, und es hat gut für mich funktioniert. Ich musste die requests-Bibliothek mocken, weil mein Ziel ist, meine Anwendung zu isolieren und keine Drittanbieter-Ressourcen zu testen.
Dann habe ich mehr über Pythons Mock-Bibliothek gelesen und festgestellt, dass ich die MockResponse-Klasse, die man einen 'Test Double' oder 'Fake' nennen könnte, durch eine python Mock-Klasse ersetzen kann.
Der Vorteil dabei ist der Zugriff auf Dinge wie assert_called_with
, call_args
und so weiter. Es sind keine zusätzlichen Bibliotheken erforderlich. Zusätzliche Vorteile wie 'Lesbarkeit' oder 'mehr Pythonic sein' sind subjektiv, daher können sie eine Rolle spielen oder auch nicht.
Hier ist meine Version, aktualisiert mit der Verwendung von Pythons Mock anstelle eines Test-Doubles:
import json
import requests
from unittest import mock
# Definition von Stubs
AUTH_TOKEN = '{"prop": "Value"}'
LIST_OF_WIDGETS = '{"widgets": ["widget1", "widget2"]}'
PURCHASED_WIDGETS = '{"widgets": ["purchased_widget"]}'
# Ausnahmeklasse, wenn eine unbekannte URL gemockt wird
class MockNotSupported(Exception):
pass
# Factory-Methode, die die Mocks erstellt
def mock_requests_factory(response_stub: str, status_code: int = 200):
return mock.Mock(**{
'json.return_value': json.loads(response_stub),
'text.return_value': response_stub,
'status_code': status_code,
'ok': status_code == 200
})
# Nebeneffekt-Mock-Funktion
def mock_requests_post(*args, **kwargs):
if args[0].endswith('/api/v1/get_auth_token'):
return mock_requests_factory(AUTH_TOKEN)
elif args[0].endswith('/api/v1/get_widgets'):
return mock_requests_factory(LIST_OF_WIDGETS)
elif args[0].endswith('/api/v1/purchased_widgets'):
return mock_requests_factory(PURCHASED_WIDGETS)
raise MockNotSupported
# requests.post patchen und Tests durchführen
with mock.patch('requests.post') as requests_post_mock:
requests_post_mock.side_effect = mock_requests_post
response = requests.post('https://myserver/api/v1/get_widgets')
assert response.ok is True
assert response.status_code == 200
assert 'widgets' in response.json()
# Jetzt kann ich auch Folgendes tun
requests_post_mock.assert_called_with('https://myserver/api/v1/get_widgets')
Repl.it-Links:
https://repl.it/@abkonsta/Using-unittestMock-for-requestspost#main.py
https://repl.it/@abkonsta/Using-test-double-for-requestspost#main.py