It's hard to say exactly what is going wrong, without seeing the call stack, but the following general pattern works.
foo.py
def foo():
pass
def bar():
result = foo()
return result["status"]
The with test_foo.py as
import mock
from foo import bar
@mock.patch("foo.foo", return_value={"status": "PASSED"})
def test_add(mock_foo):
assert bar() == "PASSED"
This general pattern works with pytest test_foo.py in the same directory.
python - Pytest mock / patch of an api call - Stack Overflow
python - How to mock requests using pytest? - Stack Overflow
python - how to mock the response from a library api in pytest - Stack Overflow
How to mock a class which is making an API call outside my function under test?
Videos
You can use requests-mock (PyPI), there is a fixture for a pytest usage.
For your example:
from correct.package import __BASE_URL
from requests import HTTPError
def test_get_employee(requests_mock):
test_id = 'random-id'
requests_mock.get(f'{__BASE_URL}/employee/{test_id}', json= {'name': 'awesome-mock'})
resp = get_employee('random-id')
assert resp == {'name': 'awesome-mock'}
def test_absent_employee(requests_mock):
test_id = 'does_not_exist'
requests_mock.get(f'{__BASE_URL}/employee/{test_id}', status_code=404)
with pytest.raises(HTTPError):
resp = get_employee(test_id)
This may help
from unittest import TestCase
import requests
import requests_mock
class TestHTTPRequest(TestCase):
def test_context_manager(self):
with requests_mock.Mocker() as mock_request:
mock_request.get("http://123-fake-api.com", text="Hello!")
response = requests.get("http://123-fake-api.com")
assert response.text == "Hello!"
Have a look at requests-mock. It provides a fixture requests_mock that you can put in your test function. In the function, you mock the API call with requests_mock.get("https://api-url"), and optionally add a response, status code, etc..
In your case you need to mock the hubspot.Client object and then mock the appropriate methods that are being called. Your function doesn't make sense just printing when there is an error, you should just let the error propagate up to the caller wherever that is coming from. I slightly modified your function to error out in order to show that and how to test both scenarios.
# src/get_events.py
from hubspot import Client
from hubspot.events.exceptions import ApiException
def get_clicked_events():
client = Client.create(api_key="YOUR_HUBSPOT_API_KEY")
try:
api_response = client.events.get_page(limit=100, event_type="clicked")
except ApiException:
raise
return api_response
from unittest.mock import patch
import pytest
from hubspot import Client
from hubspot.events.exceptions import ApiException
from src.get_events import get_clicked_events
def test_get_clicked_events_success():
with patch("src.get_events.Client", spec=Client) as mock_client:
mock_client.configure_mock(
**{
"create.return_value": mock_client,
"events.get_page.return_value": "fizz"
}
)
events = get_clicked_events()
assert events == "fizz"
def test_get_clicked_events_fail():
err_msg = "Failed to get events!"
with patch("src.get_events.Client", spec=Client) as mock_client:
mock_client.configure_mock(
**{
"create.return_value": mock_client,
"events.get_page.side_effect": ApiException(err_msg)
}
)
with pytest.raises(ApiException) as err:
get_clicked_events()
assert err_msg == err.value
Then when running from the root of the repository you can see both tests pass.
platform darwin -- Python 3.8.9, pytest-7.0.1, pluggy-1.0.0
cachedir: .pytest_cache
rootdir: ***
plugins: mock-3.7.0
collected 2 items
tests/test_script.py::test_get_clicked_events_success PASSED [ 50%]
tests/test_script.py::test_get_clicked_events_fail PASSED [100%]
=========================================================== 2 passed============================================================
» pip install pytest-mock-server