flask-testing
flask-testing copied to clipboard
Stub method when using Flask LiveServerTestCase
We're trying to test a frontend feature that sends a request to a Third Party API when a button is clicked. The click will trigger an internal API call to our Flask application, which will translate this to a request for the ThirdPartyApi.
We try to test this using Splinter, Flask Testing and PhantomJS. Because we don't want to hit the actual API, we want to stub out the method that will perform this request. However, the stub doesn't seem to work and the actual http call is performed. We suspect it has something to do with the difference between the test context and the app context, but we were not able to solve it with the app_context() provided by Flask.
Do you have suggestions how to fix this? Below is a simplified version of the test code we are using.
from splinter import Browser
from flask_testing import LiveServerTestCase
from unittest.mock import patch
class ClickButtonTest(LiveServerTestCase):
def test_click_button(self):
browser = Browser('phantomjs')
browser.visit(self.get_server_url() + "/")
with self.app.app_context():
@patch("app.lib.ThirdPartyApi")
class FakeThirdPartyApi:
def some_action(self, param):
return True
browser.find_by_text("Click me!").click()
assert browser.is_text_present("The button is clicked :)")
Unfortunately using the LiveServerTestCase means that mocking will have no effect. The app object is being deployed via the run() method and can't be modified once it has been run. You can think about this like if you ran the development server -- changes that you make to the code don't take effect (unless you're using the reloader which is a different mechanism entirely) until re-running it.
In general its better to use the regular TestCase with the fake client if you are planning on mocking. In your case it doesn't seem like that is possible. However, there are a couple of solutions that I can think of depending on what the rest of that code looks like
- When you create your
ThirdPartyApiuse the configuration environment to determine whether to instantiate the real one or some fake one (whatever that fake implementation looks like) - I don't recommend this method, but it is possible: in the create_app method, you can monkey patch the third party api if it is attached to app via a property (eg. app.third_party_api) and set it to a new implementation
Does that help?
you can patch at the time when the LiveServer is created:
@patch("util.ldapClient.LDAPCLient.connect")
@patch("util.ldapClient.LDAPCLient.login")
@patch("...")
@patch("...")
@patch("...")
@patch("...")
def __call__(self, result, *mocklist):
"""
Override the __call__ to patch the connect and login out
"""
for lmock in mocklist:
if '_mock_name' in lmock.__dict__:
self.mocks[lmock.__dict__['_mock_name']] = lmock
super(FrontendTest, self).__call__(result=result)
the expect_called() and other functions wont work tho...
Good luck