I'm trying to test an api mock call using from unittest.mock import patch
. I keep getting an AttributError
when I include .json()
in my function's response return (i.e. return response.json()
).
When I exclude the .json()
in my return statement, the test passes. I'm pretty new to testing and I can't figure out how to get around this error. Does anyone have an idea of how to get around this by keeping the .json()
in the return statment?
Here is my code for reference:
test_pytest.py
from unittest.mock import patch
from src.foo_helper import get_foo_data
@patch('requests.get',
return_value={
"version": "v1",
"greeting": "Aloha 👋"
}
)
def test_get_foo_data(mock_get, mock_json):
print("Mock_get: ", mock_get())
print("Mock_json: ", mock_json())
print("Function: ", get_open_play_data)
# print("Function call: ", get_foo_data('https://example.com',
# CONFIG['KEY'],
# CONFIG['PASSWORD']))
result = get_foo_data(
'route', 'key', 'password'
)
print("Result: ", result)
assert mock_get() == result
assert False
foo_helper.py
import requests
def get_foo_data(route, key, password) -> object:
# route should be a string
try:
response = requests.get(
route,
auth=(
key,
password
)
)
print("Response: ", response)
return response.json()
except requests.exceptions.RequestException as e:
print(f"There was a problem with your request: '{e}'")
As @LuÃsMöllmann already pointed out, the patching is incorrect. The actual usage was:
requests.get().json()
But the patching was:
requests.get.return_value = {some dict}
This means that requests.get()
will already return {some dict}
which then fails when .json()
is called.
The dictionary response must be mocked at requests.get.return_value.json.return_value
and not just the requests.get.return_value
:
@patch('requests.get')
def test_get_open_play_data(mock_get):
mock_json = {
"version": "v1",
"greeting": "Aloha 👋"
}
mock_get.return_value.json.return_value = mock_json
result = get_open_play_data(
'route', 'key', 'password'
)
print("Result: ", result)
assert mock_json == result
Don't reinvent the wheel of mocking the requests
module. Use a library such as requests_mock which does it easily for you.
import requests_mock as requests_mock_lib
def test_get_open_play_data_using_lib(requests_mock):
mock_json = {
"version": "v1",
"greeting": "Aloha 👋"
}
requests_mock.get("http://route", json=mock_json) # If you want the mock to be used on any URL, replace <"http://route"> with <requests_mock_lib.ANY>
result = get_open_play_data(
'http://route', 'key', 'password'
)
print("Result: ", result)
assert mock_json == result