I am trying to test a function which contain an API call. So in the function I have this line of code :
api_request = dict(requests.get(url_of_the_API).json())
So I tried to use patch like this :
@patch('requests.get')
def test_products_list_creator(self, mock_get):
mock_get.return_value = json.dumps({"products":
{
"name": "apple",
"categories": "fruit,red"
}
})
But at the line of my API call, python throw me this error :
AttributeError: 'str' object has no attribute 'json'
I tried to print type(requests.get(url_of_the_API}.json")) to know what it was and I got this : <class 'requests.models.Response'>
There is a lot of questions about convert a Response in dict but didn’t found any about converting a dict to a Response.
So how to make my patch callable by the method json() ?
>Solution :
Firstly we need to figure what is required by requests.models.Response‘s method .json in order to work, this can be done by scrying source code available at github – requests.models source. After reading requests.models.Response.json body we might conclude that if encoding is set, it does simply loads .text. text method has @property decorator, meaning it is computed when accessing .text, this in turn depend on .content which also is computed. After scrying .content it should be clear that if we set ._content value then it will be returned by .content, therefore to make fake Response which do support .json we need to create one and set .encoding and ._content of it, consider following example:
from requests.models import Response
resp = Response()
resp.encoding = 'ascii'
resp._content = b'{"x":100}'
print(resp.json())
output
{'x': 100}
Note that _content value needs to be bytes so if you have dict d then to get value to be put there do json.dumps(d).encode('ascii')