testing session variables and db storage in cherrypy app - python

I'm looking to write some unit tests for some cherrypy code.
Most of the unit test examples I have seen depend on os.environ and generally only test for the final response (html output) from the cherrypy apps.
I'm looking for:
testing that session variables have been set/unset for a given request (e.g., user logs in, I want to verify that his 'user' session variable is correct as well as his login time, etc...
checking values in a datastore (mysql/mongodb)
running tests in parallel. By default you access session and other information from cherrypy.cookie/cherrypy.session, etc... These are basically global. Is it possible to access this information another way?
Any other recommendations would be greatly appreciated.

You could write a small python http client and (assuming you run your server) unittest the responses.
Some libs that might be useful:
urllib
urllib2
http.client
Also you might want to check out selenium (allows you to script your browser in python for test cases).

Related

How to mock test Flask endpoints that mainly interact with 3rd party APIs?

We have developed various services using Flask, and all of them really act as an intermediary between the enduser and various 3rd party APIs (but no databases). I have developed tests using pytest with a test_client fixture etc and it works well. But each time a route/endpoint is called by one of the tests, it actually interacts with the 3rd party APIs.
What is the proper way to make mock tests in this situation? I am wondering if I should just develop an exact copy of the endpoints, but simulate the lines where requests to 3rd party APIs occur. That seems like a lot of work, but if I were to just return some expected JSON from a given endpoint then I don't think the code would be tested very well.
For scenarios where you need to call third-party API, you could consider using Pytest VCR.
It is a pytest plugin that allow recording of all http requests made inside a test method or function by using a decorator as follow.
#pytest.mark.vcr()
def my_test():
"""
Example of a function that test a client doing http requests
"""
some_client = SomeClient()
some_client.authenticate()
resource = some_client.get_resource("foo")
assert resource is not None
First time you run your test, calls are recorded into a file called a "cassette". Then subsequents run of this test will use this cassette as a kind of mock instead of sending real http calls.
It works as well if you are testing a flask application views in which https calls are done.
Be careful as this solution implies that if you change tested code in a way that add http calls, the test will break as new calls wont exists in the cassette. You will either have to delete cassette and record it again, or run your test with --vcr-record=new_episodes to add new calls to existing cassette.

Rest assured equivalent in Python for Rest API automation testing

in Java there is a rest-assured framework to make the API requests and validate the responses with various ways.
Is there any alternative in Python?
Or I should use the requests library to make the API calls and validate the responses e.g using JsonPath, XmlPath and other libraries.
Thanks in advance.
In order to simulate the same functionality as in Java's rest-assured, you can use:
Option 1
requests module along with pytest
Option 2
Use an available module pyhttptest
Here you just need to define your test-cases and request in a json file and run all your test cases using command line
And Last
My favorite and recommended one is pyresttest
pyresttest is tool for testing RESTful HTTP requests. It’s written in Python (hence the py prefix) but unless you intend to write extensions this does not require any Python programming. It will work just fine in a Ruby, Go, Node, or PHP project.
As a command line tool it works by specifying a root URL (host) address and then the path to a YAML configuration file. The configuration file enumerates a list of URLs to request and tests against the expected status code.
Cheers!!

Is there a better way to access my public api?

I am new to Flask.
I have a public api, call it api.example.com.
#app.route('/api')
def api():
name = request.args.get('name')
...
return jsonify({'address':'100 Main'})
I am building an app on top of my public api (call it www.coolapp.com), so in another app I have:
#app.route('/make_request')
def index():
params = {'name':'Fred'}
r = requests.get('http://api.example.com', params=params)
return render_template('really_cool.jinja2',address=r.text)
Both api.example.com and www.coolapp.com are hosted on the same server. It seems inefficient the way I have it (hitting the http server when I could access the api directly). Is there a more efficient way for coolapp to access the api and still be able to pass in the params that api needs?
Ultimately, with an API powered system, it's best to hit the API because:
It's user testing the API (even though you're the user, it's what others still access);
You can then scale easily - put a pool of API boxes behind a load balancer if you get big.
However, if you're developing on the same box you could make a virtual server that listens on localhost on a random port (1982) and then forwards all traffic to your api code.
To make this easier I'd abstract the API_URL into a setting in your settings.py (or whatever you are loading in to Flask) and use:
r = requests.get(app.config['API_URL'], params=params)
This will allow you to make a single change if you find using this localhost method isn't for you or you have to move off one box.
Edit
Looking at your comments you are hoping to hit the Python function directly. I don't recommend doing this (for the reasons above - using the API itself is better). I can also see an issue if you did want to do this.
First of all we have to make sure the api package is in your PYTHONPATH. Easy to do, especially if you're using virtualenvs.
We from api import views and replace our code to have r = views.api() so that it calls our api() function.
Our api() function will fail for a couple of reasons:
It uses the flask.request to extract the GET arg 'name'. Because we haven't made a request with the flask WSGI we will not have a request to use.
Even if we did manage to pass the request from the front end through to the API the second problem we have is using the jsonify({'address':'100 Main'}). This returns a Response object with an application type set for JSON (not just the JSON itself).
You would have to completely rewrite your function to take into account the Response object and handle it correctly. A real pain if you do decide to go back to an API system again...
Depending on how you structure your code, your database access, and your functions, you can simply turn the other app into package, import the relevant modules and call the functions directly.
You can find more information on modules and packages here.
Please note that, as Ewan mentioned, there's some advantages to using the API. I would advise you to use requests until you actually need faster requests (this is probably premature optimization).
Another idea that might be worth considering, depending on your particular code, is creating a library that is used by both applications.

Google App Engine Application Cache

In google app engine i have created my own user API appropriately called user so it doesn't interfere with the google app engine API users. Like most multiuser websites, two "versions" of the site are available to the user depending on whether or not they are logged in. Thus is created a file called router.py with the following code
import webapp2
from lib import user
import guest
import authorized
if user.isLoggedIn():
app = webapp2.WSGIApplication(authorized.WSGIHandler,debug=True)
else:
app = webapp2.WSGIApplication(guest.WSGIHandler,debug=True)
the guest and authorized modules are formated like your conventional application script for example:
import webapp2
import os
class MainPage(webapp2.RequestHandler):
def get(self,_random):
self.response.out.write('authorized: '+_random)
WSGIHandler = [('/(.*)', MainPage)]
Thus the router file easily selects which WSGIApplication url director to use by grabbing the WSGIHandler variable from either the guest or authorized module. However the user must close all tabs for the router to detect a change in the isLoggedIn() function. If you log in it does not recognize that you have done so until every tab is closed. I have two possible reasons for this:
isLoggedIn() uses os.environ['HTTP_COOKIE'] to retrieve cookies and see if a user is logged in, it then checks the cookie data against the database to make sure they are valid cookie. Possibly this could have an error where the cookies on the server's end aren't being refreshed when the page is? Maybe because i'm not getting the cookies from self.request.
Is it possible that in order to conserve frontend hours or something that google app engine caches the scripts from the server with in the server's memcache? i Doubt it but i am at a loss for the reason for this behavior.
Thanks in advance for the help
Edit
Upon more testing i found that as suspected the router.py file responded correctly and directed the user based in logged in when a comment was added to it. This seems to indicate caching.
Edit 2
I have uncovered some more information on the WSHI Application:
The Python runtime environment caches imported modules between requests on a single web server, similar to how a standalone Python application loads a module only once even if the module is imported by multiple files. Since WSGI handlers are modules, they are cached between requests. CGI handler scripts are only cached if they provide a main() routine; otherwise, the CGI handler script is loaded for every request.
I wonder how efficient to refresh the WSGI module somehow. This would undoubtably task the server, but solve my problem. Again, this seems to be a partial solution.
Edit 3
Again, any attempt to randomize a comment in the router.py file is ineffective. The id statement looking for user login is completely overlooked and the WSGIApplication is set to its original state. I'm not yet sure if this is due to the module cache in the webapp2 module or thanks to the module cache on the user API. I suspect the latter.
The problem is not "caching", it is just how WSGI applications work. A WSGI process stays alive for a reasonably long period of time, and serves multiple requests during that period. The app is defined when that process is started up, and does not change until the process is renewed. You should not try to do anything dynamic or request-dependent at that point.
replace router.py with:
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from lib import user
import guest
import authorized
def main():
if user.isLoggedIn():
run_wsgi_app(authorized.application)
else:
run_wsgi_app(guest.application)
if __name__ == "__main__":
main()
downgrading to the old webapp allows you to change dynamically the wsgi application. it's tested and works perfectly! The CGI adaptor run_wsgi_app allows for the webapp to change it's directory list without caching.

Preserving session ID's in django.test.client

I'm storing django's session key (request.session.session_key) in a database column-- It's an app that doesn't require logins, and sessions are a acceptable enough proxy for a unique user. It works fine, except now that I'm writing tests.
Since the test client preserves cookies, I assumed it the session id would be stable over multiple requests. It seems like this is incorrect, though.
For example, I was hoping that in...
browser=Client()
browser.post(rating_url, {'term':'Helpful', 'action':'add'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
browser.post(rating_url, {'term':'Helpful', 'action':'remove'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
... the view would receive the same session key both times. It doesn't work that way, though.
If anyone can suggest a work-around, I'd appreciate it.
There is the feature request for simplification of anonymous sessions usage in unit tests. In this ticket you can find the hard way to do it. Here is the link - https://code.djangoproject.com/ticket/10899

Categories

Resources