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 :)")
Related
I'd like to do a load test over my NLP web app using Locust. The website is simple where users only need to pass in their text and its language type, and then the results will show on the next page.
Therefore, I want to make my "locusts" to first pass in two values on the index page and then go to the corresponding page, which is supposed to be quick and easy. But my code doesn't work and the error message wrote there was something wrong with GET POST method (HTTP 405 & HTTP 500 error). Can anyone help me check my code?
from locust import HttpUser, TaskSet, between, task, SequentialTaskSet
class UserBehavior(SequentialTaskSet):
#task
def submit(self):
self.client.post('/', {'text': 'Kobe Bryant is the best NBA player.', 'language': 'en'})
#task
def get_boto(self):
self.client.get('/boto')
class WebsiteUser(HttpUser):
tasks = [UserBehavior]
wait_time = between(1, 2)
May be before post request with data user must login?
class UserBehavior(SequentialTaskSet):
def on_start(self):
self.client.post("/login", {
"username": "test_user",
"password": ""
})
A 405 sounds like you might not be sending your requests in the right way, maybe using the wrong verb. I would use a debug proxy (like Charles Proxy) to record the traffic to your site while you go through your flow so you know how the requests are structured and expected to be. Then I would create a new separate Python file and try to use Requests to get something working successfully (check out Python : Trying to POST form using requests for a POST example). Locust's HttpUser.client is based on Requests so once you get the separate Python file working and doing what you want, you should be able to drop in the same calls and replace request or session with self.client and it should work.
I have a Python script written up and the output of this script is a list.
Right now I need to get it online and make it accessible to others. I looked at Django , but then I realized that it may be kind of hard to create the UI. Is there any simple way to create a UI in Django and map it to an existing Python script.
Right now I using nltk, numpy, sqlite3 and things like that. Or is there a simpler way by which I can proceed?
In your case, Django is redundant.
You can use something smaller, Flask or maybe Aiohttp.
For example, all you need in aiohttp:
basic hmtl template
handler for one url (here you will call your script)
aiohttp webserver
The main idea:
Your server catch some url (for example /),
start your script, receives result,
respond with your html template (also render script result in it).
You can try creating a flask App.
Just do a pip install Flask and try the code below
from flask import Flask
import flask
import json
from flask import Response
app = Flask(__name__)
#app.route('/test',methods=['GET'])
def test():
'''
GET: Receives the request in /test route and returns a response containing {"response": [1,2,3]}
'''
my_list = [1,2,3]
resp = Response(response=json.dumps({"response": my_list}), status=200, mimetype='application/json')
return resp
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=8082)
Then to test your app from your browser accessing
localhost:8082/test
or also through some app like postman
I would suggest looking into something like React for creating the UI. This way your UI would only make calls to your Flask server.
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)
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")
Is there a way to call a python function when a certain link is clicked within a html page?
Thanks
You'll need to use a web framework to route the requests to Python, as you can't do that with just HTML. Flask is one simple framework:
server.py:
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def index():
return render_template('template.html')
#app.route('/my-link/')
def my_link():
print 'I got clicked!'
return 'Click.'
if __name__ == '__main__':
app.run(debug=True)
templates/template.html:
<!doctype html>
<title>Test</title>
<meta charset=utf-8>
Click me
Run it with python server.py and then navigate to http://localhost:5000/. The development server isn't secure, so for deploying your application, look at http://flask.pocoo.org/docs/0.10/quickstart/#deploying-to-a-web-server
Yes, but not directly; you can set the onclick handler to invoke a JavaScript function that will construct an XMLHttpRequest object and send a request to a page on your server. That page on your server can, in turn, be implemented using Python and do whatever it would need to do.
Yes. If the link points to your web server, then you can set up your web server to run any kind of code when that link is clicked, and return the result of that code to the user's browser. There are many ways to write a web server like this. For example, see Django. You might also want to use AJAX.
If you want to run code in the user's browser, use Javascript.
There are several ways to do this, but the one that has worked best for me is to use CherryPy. CherryPy is a minimalist python web framework that allows you to run a small server on any computer. There is a very similiar question to yours on stackoverflow - Using the browser for desktop UI.
The code below will do what you want. Its example 2 from the CherryPy tutorial.
import cherrypy
class HelloWorld:
def index(self):
# Let's link to another method here.
return 'We have an important message for you!'
index.exposed = True
def showMessage(self):
# Here's the important message!
return "Hello world!"
showMessage.exposed = True
import os.path
tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf')
if __name__ == '__main__':
# CherryPy always starts with app.root when trying to map request URIs
# to objects, so we need to mount a request handler root. A request
# to '/' will be mapped to HelloWorld().index().
cherrypy.quickstart(HelloWorld(), config=tutconf)
else:
# This branch is for the test suite; you can ignore it.
cherrypy.tree.mount(HelloWorld(), config=tutconf)
I personally use CherryPy in combination with several other modules and tools:
Mako (template library)
py2exe (convert into Windows executable)
GccWinBinaries (used in combination with py2exe)
I wrote an article about Browser as Desktop UI with CherryPy that introduces modules and tools used plus some further links that might help.
In addition to running Python scripts on a server, you can run Python scripts on the client-side using Skulpt.