Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate URLs for Flask test client with url_for function

I'm trying to write unit tests for a Flask app using pytest. I have an app factory:

def create_app():
    from flask import Flask
    app = Flask(__name__)
    app.config.from_object('config')
    import os
    app.secret_key = os.urandom(24)
    from models import db
    db.init_app(app)
    return app

And a test class:

class TestViews(object):

    @classmethod
    def setup_class(cls):
        cls.app = create_app()
        cls.app.testing = True
        cls.client = cls.app.test_client()

    @classmethod
    def teardown_class(cls):
        cls.app_context.pop()

    def test_create_user(self):
        """
        Tests the creation of a new user.
        """
        view = TestViews.client.get(url_for('create_users')).status_code == 200

but when I run my tests I get the following error:

RuntimeError: Attempted to generate a URL without the application context being pushed. This has to be executed when application context is available.

Googling this tells me (I think) that using the test client should create an automatic application context. What am I missing?

like image 628
ruipacheco Avatar asked Oct 09 '17 12:10

ruipacheco


People also ask

How do I generate a URL in flask?

The url_for() function is used to build a URL to the specific function dynamically. The first argument is the name of the specified function, and then we can pass any number of keyword argument corresponding to the variable part of the URL.

What is url_for function in flask?

url_for in Flask is used for creating a URL to prevent the overhead of having to change URLs throughout an application (including in templates). Without url_for , if there is a change in the root URL of your app then you have to change it in every page where the link is present.

Which function is used to create a URL in HTML using flask Python?

Python for web development using Flask The url_for() function is very useful for dynamically building a URL for a specific function. The function accepts the name of a function as first argument, and one or more keyword arguments, each corresponding to the variable part of URL.


1 Answers

Making requests with the test client does indeed push an app context (indirectly). However, you're confusing the fact that url_for is visually inside the test request call with the idea that it is actually called inside. The url_for call is evaluated first, the result is passed to client.get.

url_for is typically for generating URLs within the app, unit tests are external. Typically, you just write exactly the URL you're trying to test in the request instead of generating it.

self.client.get('/users/create')

If you really want to use url_for here, you must do it in an app context. Note that when you're in an app context but not a request context, you must set the SERVER_NAME config and also pass _external=False. But again, you should probably just write out the URL you're trying to test.

app.config['SERVER_NAME'] = 'localhost'

with self.app.app_context():
    url = url_for(..., _external=False)

self.client.get(url, ...)
like image 134
davidism Avatar answered Oct 21 '22 01:10

davidism