Mock 3rd party website for local development with Python requests library - python

I'm building a (facebook connected) web server using Flask. Here's an example route
#app.route('/login', methods=['GET'])
def login():
graph = facebook.GraphAPI(request.args.get('access_token'))
profile = graph.get_object('me')
return jsonify(profile)
This works fine, but it seems bad practice to be continually hitting Facebook servers when I'm doing local dev.
What is the most effective way to re-route the facebook API to mocks or even a mock server? Internally, the facebook-sdk library uses requests to reach graph.facebook.com.
I've seen this question
python mock Requests and the response
and in particular, Dropbox's responses library, but it looks like you have to wrap each call in their decorator. It would work well for a unit testing suite, but I'm just interested in doing development against mock data and mock responses.
Update: In response to Thomas, I had been thinking about a similar solution. I tried adding:
if config_name == 'development':
print 'monkey'
import requests
def mock(*args, **kwargs):
print args, kwargs
return {}
requests.request = mock
But that didn't seem to change the behavior of the facebook-sdk library.

You could check if debug mode is on using app.config, and then (if debug mode is on), turn your requests into dummy requests. I'm not that familiar with the facebook API, so (unfortunately) I can't write out the dummy code for you.

How about using the flask-testing and mock libraries:
import requests
from flask.ext.testing import TestCase
from mock import Mock
class TestLogin(TestCase):
def setUp(self):
requests.request = Mock()
super(TestLogin, self).setUp()
def test_it(self):
resp = self.client.get('/login')
self.assertEquals('right stuff', resp.data)

Related

how to write test cases for authenticated urls in flask

I am using flask with mongoengine and Login Manager for session maintaining. I want to write test cases for authenticated views. can any one help/suggestions regarding this.
First off, I recommend using pytest, and the flask-pytest library which contains some great convenience features to make all of this easier.
flask-pytest comes out of the box with a client fixture, which, per the docs, refers to Flask.test_client
What you want to do is mimic a valid session (e.g. however you app is validating that a user is "logged in").
Here is how to do this without any supporting libraries:
import app
from flask import url_for
def test_authenticated_route():
app.testing = True
client = app.test_client()
with client.session_transaction() as sess:
# here you can assign whatever you need to
# emulate a "logged in" user...
sess["user"] = {"email": "test_user#example.com"}
# now, you can access "authenticated" endpoints
response = client.get(url_for(".protected_route"))
assert response.status_code == 200
This is also discussed in the Flask docs.

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.
Does anybody know 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 :)")

Cleanly Mocking Remote Servers and APIs for Django Unittests

I have a thorny problem that I can't seem to get to grips with. I am
currently writing unit tests for a django custom auth-backend. On our
system we actually have two backends: one the built-in django backend
and the custom backend that sends out requests to a Java based API
that returns user info in the form of XML. Now, I am writing unit
tests so I don't want to be sending requests outside the system like
that, I'm not trying to test the Java API, so my question is how can I
get around this and mock the side-effects in the most robust way.
The function I am testing is something like this, where the url
settings value is just the base url for the Java server that
authenticates the username and password data and returns the xml, and the service value is
just some magic for building the url query, its unimportant for
us:
#staticmethod
def get_info_from_api_with_un_pw(username, password, service=12345):
url = settings.AUTHENTICATE_URL_VIA_PASSWORD
if AUTH_FIELD == "username":
params = {"nick": username, "password": password}
elif AUTH_FIELD == "email":
params = {"email": username, "password": password}
params["service"] = service
encoded_params = urlencode([(k, smart_str(v, "latin1")) for k, v in params.items()])
try:
# get the user's data from the api
xml = urlopen(url + encoded_params).read()
userinfo = dict((e.tag, smart_unicode(e.text, strings_only=True))
for e in ET.fromstring(xml).getchildren())
if "nil" in userinfo:
return userinfo
else:
return None
So, we get the xml, parse it into a dict and if the key nil is present
then we can return the dict and carry on happy and authenticated.
Clearly, one solution is just to find a way to somehow override or
monkeypatch the logic in the xml variable, I found this answer:
How can one mock/stub python module like urllib
I tried to implement something like that, but the details there are
very sketchy and I couldn't seem to get that working.
I also captured the xml response and put it in a local file in the
test folder with the intention of finding a way to use that as a mock
response that is passed into the url parameter of the test function,
something like this will override the url:
#override_settings(AUTHENTICATE_URL_VIA_PASSWORD=(os.path.join(os.path.dirname(__file__), "{0}".format("response.xml"))))
def test_get_user_info_username(self):
self.backend = RemoteAuthBackend()
self.backend.get_info_from_api_with_un_pw("user", "pass")
But that also needs to take account of the url building logic that the
function defines, (i.e. "url + encoded_params"). Again, I could rename
the response file to be the same as the concatenated url but this is becoming
less like a good unit-test for the function and more of a "cheat", the whole
thing is just getting more and more brittle all the time with these solutions, and its really just a fixture anyway, which is also something I want to avoid if
at all possible.
I also wondered if there might be a way to serve the xml on the django development server and then point the function at that? It seems like a saner solution, but much googling gave me no clues if such a thing would be possible or advisable and even then I don't think that would be a test to run outside of the development environment.
So, ideally, I need to be able to somehow mock a "server" to
take the place of the Java API in the function call, or somehow serve
up some xml payload that the function can open as its url, or
monkeypatch the function from the test itself, or...
Does the mock library have the appropriate tools to do such things?
http://www.voidspace.org.uk/python/mock
So, there are two points to this question 1) I would like to solve my
particular problem in a clean way, and more importantly 2) what are
the best practices for cleanly writing Django unit-tests when you are
dependent on data, cookies, etc. for user authentication from a remote
API that is outside of your domain?
The mock library should work if used properly. I prefer the minimock library and I wrote a small base unit testcase (minimocktest) that helps with this.
If you want to integrate this testcase with Django to test urllib you can do it as follows:
from minimocktest import MockTestCase
from django.test import TestCase
from django.test.client import Client
class DjangoTestCase(TestCase, MockTestCase):
'''
A TestCase class that combines minimocktest and django.test.TestCase
'''
def _pre_setup(self):
MockTestCase.setUp(self)
TestCase._pre_setup(self)
# optional: shortcut client handle for quick testing
self.client = Client()
def _post_teardown(self):
TestCase._post_teardown(self)
MockTestCase.tearDown(self)
Now you can use this testcase instead of using the Django test case directly:
class MySimpleTestCase(DjangoTestCase):
def setUp(self):
self.file = StringIO.StringIO('MiniMockTest')
self.file.close = self.Mock('file_close_function')
def test_urldump_dumpsContentProperly(self):
self.mock('urllib2.urlopen', returns=self.file)
self.assertEquals(urldump('http://pykler.github.com'), 'MiniMockTest')
self.assertSameTrace('\n'.join([
"Called urllib2.urlopen('http://pykler.github.com')",
"Called file_close_function()",
]))
urllib2.urlopen('anything')
self.mock('urllib2.urlopen', returns=self.file, tracker=None)
urllib2.urlopen('this is not tracked')
self.assertTrace("Called urllib2.urlopen('anything')")
self.assertTrace("Called urllib2.urlopen('this is mocked but not tracked')", includes=False)
self.assertSameTrace('\n'.join([
"Called urllib2.urlopen('http://pykler.github.com')",
"Called file_close_function()",
"Called urllib2.urlopen('anything')",
]))
Here's the basics of the solution that I ended up with for the record. I used the Mock library itself rather than Mockito in the end, but the idea is the same:
from mock import patch
#override_settings(AUTHENTICATE_LOGIN_FIELD="username")
#patch("mymodule.auth_backend.urlopen")
def test_get_user_info_username(self, urlopen_override):
response = "file://" + os.path.join(os.path.dirname(__file__), "{0}".format("response.xml"))
# mock patch replaces API call
urlopen_override.return_value = urlopen(response)
# call the patched object
userinfo = RemoteAuthBackend.get_info_from_api_with_un_pw("user", "pass")
assert_equal(type(userinfo), dict)
assert_equal(userinfo["nick"], "user")
assert_equal(userinfo["pass"], "pass")

Dumping HTTP requests with Flask

I am developing a Flask application based web application ( https://github.com/opensourcehacker/sevabot ) which has HTTP based API services.
Many developers are using and extending the API and I'd like to add a feature which prints Flask's HTTP request to Python logging output, so you can see raw HTTP payloads, source IP and headers you get.
What hooks Flask offers where this kind of HTTP request dumping would be the easiest to implement
Are there any existing solutions and best practices to learn from?
Flask makes a standard logger available at at current_app.logger, there's an example configuration in this gist, though you can centralise the logging calls in a before_request handler if you want to log every request:
from flask import request, current_app
#app.before_request
def log_request():
if current_app.config.get('LOG_REQUESTS'):
current_app.logger.debug('whatever')
# Or if you dont want to use a logger, implement
# whatever system you prefer here
# print request.headers
# open(current_app.config['REQUEST_LOG_FILE'], 'w').write('...')

Creating a mock web service from a WSDL file in Python

We are writing a client for a remote service that exposes SOAP web services and publishes a WSDL definition for those services.
We don't have access to the system during testing, so we'd like to write a mock service. We're using Python for the client, so ideally we'd want to use Python for the mock server, although I suppose it's not strictly necessary.
The dream would be to be able to generate stubs from the WSDL file which we could fill in, and then serve those using Paste Deploy as a WSGI server, although it doesn't have to be Paste Deploy or WSGI so long as it works reliably. The main thing is that we need to be generating the stubs from the "real" WSDL file so that we don't accidentally write a non-compliant mock server.
We're using suds for the client side library, and have looked at soaplib and ZSI. However, the wsgi2py stuff in soaplib says "do not use" at the top and ZSI seems like a lot to swallow. What do people generally use for this kind of thing?
Martin
As a mock server I would really recommend soapUI (http://www.soapui.org).
It takes a WSDL and generates the services and service methods automatically. You can then go on and define static returns or dynamic ones using Groovy scripts. Take a look here for the documentation of web service mocking.
soapUI comes in a free and paid pro version. I have used the free version with great success.
I would recommend you use soapUI for creating a mock service. It's very easy to install. It's just as easy to create a WS mock service.
It takes the WSDL file from your desired location, it creates the structure for the requests and if you wish, it also creates the mock web service with the intended structure drawn from the WSDL file.
When you create the new soapUI project, select the third checkbox option to create the mock web service.
If xsd schema files are required, make sure they are well referenced from the WSDL file.
It doesn't use python but if all you need is a test environment that you can send requests and get responses, that will be more than enough.
I hope that helps.
You could use this code for creating a suds mock client.
from suds.client import Client
class AlwaysCallable(object):
"""
Represents a chainable-access object and proxies calls to ClientMock.
"""
name = None
def __init__(self, client_cls):
self._client_cls = client_cls
def __call__(self, *args, **kwargs):
try:
hook = object.__getattribute__(self._client_cls, self.name)
except AttributeError:
pass
else:
return hook(self._client_cls, *args, **kwargs)
def __getattr__(self, item):
new = object.__getattribute__(self, '__class__')(self._client_cls)
new.name = item
return new
class ClientMock(Client):
"""
Abstract mock suds client.
"""
def __init__(self, url, **kwargs):
pass
def __getattr__(self, item):
return AlwaysCallable(self.__class__)
def __unicode__(self):
return 'Client mock'
def __str__(self):
return 'Client mock'
And next define a concrete ClientMock.
class UserCredentialsServiceClientMock(ClientMock):
"""
Mock object that implements remote side services.
"""
def GetUserInfo(cls, user_id):
"""
Stub for remote service.
"""
return UserInfo(id=user_id, name='Adam Smith')
Now you could use mock library to spoof a code, that uses suds.client.Client.
from unittest import TestCase
from mock import patch
from project.api import get_user_credentials
class UserCredentialsClientTestCase(TestCase):
def test_getting_user_credentials(self):
with patch('project.api.Client', new=UserCredentialsServiceClientMock):
self.assertEquals(get_user_credentials(1), 'Adam Smith')

Categories