使用url_for函数为Flask测试客户端生成URL

9

我将尝试使用pytest为Flask应用编写单元测试。 我有一个应用工厂:

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

还有一个测试类:

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

但是当我运行我的测试时,我会得到以下错误:
RuntimeError: Attempted to generate a URL without the application context being pushed. This has to be executed when application context is available.

搜索得知(我认为),使用测试客户端应该会创建一个自动应用程序上下文。我错过了什么?
2个回答

13

使用测试客户端发出请求确实会推送应用上下文(间接地)。但是,你混淆了url_for在测试请求调用中的视觉位置和它实际被调用的想法。 url_for调用首先被求值,结果传递给client.get

url_for通常用于生成应用内URL,在单元测试中是外部的。通常,您只需在请求中直接编写要测试的URL,而不是生成它。

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

如果你真的想在这里使用url_for,你必须在应用上下文中这样做。请注意,当你处于应用上下文但不是请求上下文时,你必须设置SERVER_NAME配置,并且传递_external=False。但是,你最好直接编写你尝试测试的URL。

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

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

self.client.get(url, ...)

5

您可以在使用app.test_request_context()方法创建的测试请求上下文中调用url_for()。有三种方法可以实现这一点。

使用设置和拆卸

由于您已经创建了设置和拆卸方法,就像我通常在unittest中所做的那样,您可以在设置方法中推送一个测试请求上下文,然后在拆卸方法中弹出它:

class TestViews(object):

    @classmethod
    def setup_class(cls):
        cls.app = create_app()
        cls.app.testing = True
        cls.client = cls.app.test_client()
        cls.context = cls.app.test_request_context()  # create the context object
        cls.context.push()  # push the context

    @classmethod
    def teardown_class(cls):
        cls.context.pop()  # pop the context

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

使用pytest-flask

此外,你也可以使用pytest-flask。通过pytest-flask,你可以无需上下文管理器即可访问上下文绑定对象(如url_for、request和session):

def test_app(client):
    assert client.get(url_for('myview')).status_code == 200

使用autouse fixture

如果您不想安装该插件,您可以使用以下装置来执行类似操作(从pytest-flask的源代码中借鉴):

@pytest.fixture
def app():
    app = create_app('testing')
    return app


@pytest.fixture(autouse=True)
def _push_request_context(request, app):
    ctx = app.test_request_context()  # create context
    ctx.push()  # push

    def teardown():
        ctx.pop()  # pop

    request.addfinalizer(teardown)  # set teardown

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接