Testing Marker routes are executed and do not exist
I am creating a large number of Flask routes using regular expressions . I would like to have a unit test that checks for correct routes and incorrect 404 routes.
One way to do this is to deploy a local server and use urllib2.urlopen
or the like. However, I would like to be able to run this test on Travis, and I assume this is not an option.
Is there any other way to check the routes in my application?
source to share
Use the objectFlask.test_client()
in your unit tests. The method returns an instanceFlaskClient
( subclasswerkzeug.test.TestClient
), which makes it trivial for testing routes.
The result of the call TestClient
is an objectResponse
to see if the 200 or 404 response is an attributeResponse.status_code
test :
with app.test_client() as c:
response = c.get('/some/path/that/exists')
self.assertEquals(response.status_code, 200)
or
with app.test_client() as c:
response = c.get('/some/path/that/doesnt/exist')
self.assertEquals(response.status_code, 404)
See the chapter " Testing Flask Applications " in the Flask documentation.
source to share
Martjin's answer probably solves your problem, but sometimes you don't (or will) have time to mock all the components you call in the route you want to test for existence.
And why do you need to make fun of? Well, the call get('some_route')
first checks to see if this route exists and then ... it gets executed!
If the view is complex and you need to have fixtures, envs variables and any other preparation just for the test if the route exists, then you need to think again about your test design.
How to avoid this:
You can list all routes in your application. The list contains the check you are testing.
In the following example, you can see this in practice with a sitemap implementation.
from flask import Flask, url_for
app = Flask(__name__)
def has_no_empty_params(rule):
defaults = rule.defaults if rule.defaults is not None else ()
arguments = rule.arguments if rule.arguments is not None else ()
return len(defaults) >= len(arguments)
@app.route("/site-map")
def site_map():
links = []
for rule in app.url_map.iter_rules():
# Filter out rules we can't navigate to in a browser
# and rules that require parameters
if "GET" in rule.methods and has_no_empty_params(rule):
url = url_for(rule.endpoint, **(rule.defaults or {}))
links.append((url, rule.endpoint))
# links is now a list of url, endpoint tuples
links:
source to share
Another way to validate the URL without executing the attached view function is to use the . match
MapAdapter
from flask import Flask
app = Flask(__name__)
@app.route('/users')
def list_users():
return ''
@app.route('/users/<int:id>')
def get_user(id):
return ''
testing
# Get a new MapAdapter instance. For testing purpose, an empty string is fine
# for the server name.
adapter = app.url_map.bind('')
# This raise werkzeug.exceptions.NotFound.
adapter.match('/unknown')
# This raises werkzeug.exceptions.MethodNotAllowed,
# Although the route exists, the POST method was not defined.
adapter.match('/users', method='POST')
# No exception occurs when there is a match..
adapter.match('/users')
adapter.match('/users/1')
From Werkzeug documentation:
You get a tuple in the form (endpoint, arguments) if there is a match.
Which can be useful in certain testing scenarios.
source to share