I am trying to build out some tests for a Flask application and I'm struggling to get some of the mocking/patching working as expected.
Despite spending time reading/thinking through the documentation around where to patch, neither @patch
or monkeypatch
appear to behave as I expect and I'm struggling to see what I'm doing wrong.
In the Flask api.py
file I have a simple login API that checks an auth requirement (defined elsewhere and imported as shown):
from project_name.api.auth import login_auth
@api.route('/v1/login', methods=['POST'])
data = request.get_json()
username = data['Username']
password = data['Password']
if not login_auth(username, password):
raise APIError('Invalid Username or Password')
...
and I'm interested in patching the login_auth
function so that I can test without a real username/password.
In my pytest file, I have attempted to use both patch and monkeypatch to solve this.
@patch
approach:
@patch('project_name.api.auth.login_auth')
def test_login(mock_login_auth, client):
mock_login_auth.return_value = True
mimetype = 'application/json'
headers = {
'Content-Type': mimetype,
'Accept': mimetype
}
data = {
'Username': "test_user",
'Password': "test_password",
}
url = 'api/v1/login'
assert project_name.api.auth.login_auth('x', 'y') == True
response = client.post(url, data=json.dumps(data), headers=headers)
assert response.status_code == 200
And if I run this test then the first assert statement which calls the patched function directly will work as expected, however the API call will not use the mocked login_auth
function and the test will fail this criteria.
monkeypatch
approach:
def test_login2(client, monkeypatch):
monkeypatch.setattr("project_name.api.auth.login_auth", lambda x, y: True)
mimetype = 'application/json'
headers = {
'Content-Type': mimetype,
'Accept': mimetype
}
data = {
'Username': "test_user",
'Password': "test_password",
}
url = 'api/v1/login'
assert project_name.api.auth.login_auth('x', 'y') == True
response = client.post(url, data=json.dumps(data), headers=headers)
assert response.status_code == 200
And again, I see the first assert, that calls the function directly, being patched as expected but the function that is being called after the request to the API has not been patched so the test will fail on the second assert
statement.
I've tried a number of different approaches, including trying to patch the login_auth
at the path project_name.api.login_auth
(under the assumption that I'm trying to patch the specific login_auth function that gets imported into the api.py
file) but the right approach is not clear to me.
I'm wondering if there is something specific I need to do given that I'm using Flask's test_client approach, or whether there is something else I'm missing.