xiº
xiº

Reputation: 4687

Correct testing with request context in Flask

I am trying to perform some tests with calling route functions explicitly.

from flask import Flask
app = Flask(__name__)


@app.route("/")
def index():
    myfunc()
    return "Index!"

@app.route("/a")
def hello():
    return "hello"

def myfunc():
    with app.test_request_context('/', method='POST'):
        app.hello()


if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True)

But it fails with:

Traceback (most recent call last):
  File "python2.7/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "python2.7/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "test.py", line 9, in index
    myfunc()
  File "test.py", line 18, in myfunc
    app.hello()
AttributeError: 'Flask' object has no attribute 'hello'

Is it possible to test routing function by this way?

Yep example is a little bit ugly but I need to figure out what is wrong with it.

Upvotes: 0

Views: 4204

Answers (2)

davidism
davidism

Reputation: 127390

To perform an "internal redirect", or call a view from another view, you push a new request context with the correct url and any other required data, then let Flask dispatch the request. You can return the value from the inner view, or your own response, in the outer view.

from flask import Flask, request, url_for

app = Flask(__name__)

@app.route('/')
def index():
    with app.test_request_context(
            url_for('hello'),
            headers=request.headers.to_list(),
            query_string=request.query_string
    ):
        return app.dispatch_request()

@app.route('/greet')
def hello():
    return 'Hello, {}!'.format(request.args.get('name', 'World'))

app.run()

Navigating to http://127.0.0.1/?name=davidism returns Hello, davidism!, the response from the hello view.


You would not test views by calling them from a running application like this. To test a Flask application, you would use unit tests and the test client as described in the docs.

with app.test_client() as c:
    r = c.get('/a')
    assert r.data.decode() == 'hello'

Upvotes: 3

kristaps
kristaps

Reputation: 1723

hello is a regular function, decorating it with app.route won't add it to the app object. Did you perhaps mean to just invoke the hello function, like this:

with ...:
    hello()

Upvotes: 0

Related Questions