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?

+8


source to share


3 answers


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.

+11


source


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:

get a list of all routes defined in the application

Assistant for a list of routes (e.g. rake routes)

+2


source


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.

+1


source







All Articles