If you are looking for python library for testing your consumption of 3rd party API you can give a try to this library (responses
see https://github.com/getsentry/responses ) allowing you to test arbitrary requests scenarios with mocked responses.
Idea is simply:
you hardcode the desired response in some dict
you create mock of the certain url so the real request does not go somewhere in the web, but uses the mocked data and provided status code etc. what you configured using responses.add
and it is valid in the scope of decorated method with @responses.activate
Basic example:
Example test - which is testing either my method reverse_geocoding(latitude, longitude)
extract desired things from the whole response it gets from Google Maps API:
import json
import responses
from django.conf import settings
from django.test import TestCase
from utils.geocoding import reverse_geocoding , REVERSE_GEOCODING_URL
RESPONSE_GEOCODING_MOCK = {
'results' : [
{
'address_components' : [
{ 'long_name' : '74' , 'short_name' : '74' , 'types' : [ 'street_number' ]},
{ 'long_name' : 'Mickiewicza' , 'short_name' : 'Mickiewicza' , 'types' : [ 'route' ]},
{ 'long_name' : 'Żoliborz' , 'short_name' : 'Żoliborz' , 'types' : [ 'political' , 'sublocality' , 'sublocality_level_1' ]},
{ 'long_name' : 'Warszawa' , 'short_name' : 'Warszawa' , 'types' : [ 'locality' , 'political' ]},
{ 'long_name' : 'Warszawa' , 'short_name' : 'Warszawa' , 'types' : [ 'administrative_area_level_2' , 'political' ]},
{ 'long_name' : 'mazowieckie' , 'short_name' : 'mazowieckie' , 'types' : [ 'administrative_area_level_1' , 'political' ]},
{ 'long_name' : 'Poland' , 'short_name' : 'PL' , 'types' : [ 'country' , 'political' ]}
],
'formatted_address' : 'Mickiewicza 74, Warszawa, Poland' ,
'geometry' : { 'location' : { 'lat' : 52.2790223 , 'lng' : 20.980648 },
'location_type' : 'ROOFTOP' ,
'viewport' : { 'northeast' : { 'lat' : 52.2803712802915 , 'lng' : 20.9819969802915 },
'southwest' : { 'lat' : 52.2776733197085 , 'lng' : 20.9792990197085 }}
},
'place_id' : 'ChIJxXoMrOfLHkcRBAFsrjKGcMc' ,
'types' : [ 'street_address' ]
}
],
'status' : 'OK'
}
class TestGoogleAPIGeocodingConsumer ( TestCase ):
@ responses . activate
def test_geocoding ( self ):
latitude , longitude = 52.27904 , 20.980366
responses . add (
responses . GET ,
REVERSE_GEOCODING_URL . format (
latitude = latitude ,
longitude = longitude ,
api_key = settings . GOOGLE_API_KEY
),
body = json . dumps ( RESPONSE_GEOCODING_MOCK ),
content_type = "application/json" )
response = reverse_geocoding ( latitude , longitude )
self . assertEqual ( response , { 'address_city' : 'Warszawa' ,
'address_country' : 'Poland' ,
'address_number' : '74' ,
'address_street' : 'Mickiewicza' })
the tested method for reference utils/geocoding.py
:
REVERSE_GEOCODING_URL = "https://maps.googleapis.com/maps/api/geocode/json?latlng={latitude},{longitude}&key={api_key}"
def reverse_geocoding ( latitude , longitude ):
url = REVERSE_GEOCODING_URL . format (
latitude = latitude ,
longitude = longitude ,
api_key = settings . GOOGLE_API_KEY
)
response = requests . get ( url )
info = response . json ()
address = {}
for component in info [ 'results' ][ 0 ][ 'address_components' ]:
if 'street_number' in component . get ( 'types' ):
address [ 'address_number' ] = component [ 'long_name' ]
if 'route' in component . get ( 'types' ):
address [ 'address_street' ] = component [ 'long_name' ]
if 'locality' in component . get ( 'types' ):
address [ 'address_city' ] = component [ 'long_name' ]
if 'country' in component . get ( 'types' ):
address [ 'address_country' ] = component [ 'long_name' ]
return address
More sophisticated one:
Let’s use custom calback doing something based on requests, and in this example setting value in session.
import json
import responses
import requests
from django.test import TestCase
PAYMENT_ID_PAY_PAL = 'PAY_PAL'
PAYMENT_METHOD_KEY_NAME = 'SESSION_KEY_NAME_FOR_PAYMENT_METHOD'
class MockedPaymentMethodTest ( TestCase ):
@ responses . activate
def test_setting_payment_method_id_in_session ( self ):
# make sure that after PUT request with payment method
# we store info about it in session
url = 'http://example.com:8080/payment_metod/'
payment_method_id = PAYMENT_ID_PAY_PAL
s = requests . Session ()
def request_callback ( request ):
data = json . loads ( request . body )
resp_body = { u 'status' : u 'Ok' }
s . cookies [ PAYMENT_METHOD_KEY_NAME ] = data . get ( 'payment_method_id' )
return 201 , {}, json . dumps ( resp_body )
responses . add_callback (
responses . PUT ,
url ,
callback = request_callback ,
content_type = 'application/json' ,
)
response = s . put (
url ,
json . dumps ({ 'payment_method_id' : payment_method_id }),
headers = { 'content-type' : 'application/json' }
)
self . assertEqual ( response . status_code , 201 )
self . assertEqual (
s . cookies [ PAYMENT_METHOD_KEY_NAME ], payment_method_id
)