I have a python application which uses Flask to expose some endpoints. Also, I'm using a fixture
, to catch unhandled exceptions and to return a custom response. This is a sample code:
from flask import make_response, Blueprint
root = Blueprint("main", __name__)
@root.errorhandler(Exception)
def custom_error_handler(error):
#do other things here
return make_response({"status": "failure", "error": str(error)}), 500
@root.route("/my_url", methods=["POST"])
def my_url_method():
#do other thins
return make_response(...), 200
I want to have a test to ensure this works. So, in order to simulate that an unhandled exception has occurred, I'm trying to mock my_url method
with a function that simply raise an exception:
from unittest.mock import patch
from flask import Flask
@pytest.fixture
def client(monkeypatch):
app = Flask(__name__, instance_relative_config=True)
app.register_blueprint(root)
app.config["TESTING"] = True
return app.test_client()
def test_exception(client):
with patch("[file_link].my_url_method", side_effect=Exception("an error")):
response = client.post("my_url")
assert response.status_code == 500
However assertion fails. The method is executed correctly as is not raised any exception, returning 200 as status code.
I think the problem is that mock is not applied when you call the method throw flask. But I don't know how to fix it.
I found a solution. It's not the most elegant one, but it works. Patching the test with a decorator, works because the patch it's apply before the flask context is created:
@patch("[file_link].my_url_method", side_effect=Exception("an error")
def test_exception(client):
#some code here
Noticing that, gives me the clue, that the problem relies on flask initialization and pytest fixture creation.
However, doing that way interferes with the creation of flask context, and the decorators applied on each mocked method are not applied correctly.
So, instead of doing a "traditional mock", I'm simply updating the flask reference for the function it have to call on the request:
def mocked_function(**args):
raise Exception(MOCKED_EXCEPTION_MESSAGE)
def test_exception(client):
client.application.view_functions["main.my_url_method"] = mocked_function
The client
fixture it's created for each test, so it does not interfere either on the rest of the tests in the suite.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments