Flask pytest测试函数使用g

6
我正在使用Flask Cookiecutter构建我的测试,所有其他测试都正常工作。只有当我测试一个使用g元素的函数时,例如在我的views.py文件中的g.user,才会出现问题。
我的conftest.py与flask-cookiecutter完全相同,另外还添加了来自Flask-Testing的伪造资源和上下文技巧
### conftest.py ###
...
from contextlib import contextmanager
from flask import appcontext_pushed, g

@contextmanager
def user_set(app, user):
    def handler(sender, **kwargs):
        g.user = user

    with appcontext_pushed.connected_to(handler, app):
        yield
...

这是我的测试文件:

### test_file.py ###
from .conftest import user_set
import pytest
from my_app.utils import presave_posted_settings # <-- fn I want to test

@pytest.fixture()
def form_data():
    return {...bunch of data..}

@pytest.mark.usefixtures("form_data")
class TestPresaveSettings:
    """Test cases for checking attributes before saving"""
    def test_presave_posted_settings(self, form_data, user, testapp):
        """User meals are selected in form"""
        with user_set(testapp, user):  #<-- testapp and user available from flask-cookiecutter conftest.py
            assert presave_posted_settings(form_data)

当我在test_file.py上运行测试时,我看到:
user = <User 'user0'>, testapp = <webtest.app.TestApp object at 0x1101ee160>

def test_presave_posted_settings(self, form_data, user, testapp):
    """User meals are selected in form"""
    with user_set(testapp, user):
>           assert presave_posted_settings(form_data)

test_utils.py:20: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _  
../my_app/utils.py:26: in presave_posted_settings
g.user.breakfast = g.user.lunch = g.user.dinner = g.user.snack = g.user.dessert = False
 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _  
 self = <flask.g of 'my_app'>, name = 'user'

 def __getattr__(self, name):
    if name == '__members__':
        return dir(self._get_current_object())
>       return getattr(self._get_current_object(), name)
E       AttributeError: '_AppCtxGlobals' object has no attribute 'user'

我已经搜索过了,大多数例子使用Unittest或将所有pytest测试放在一个文件中。 我想坚持采用具有多个测试文件的模式,每个文件都利用conftest.py,但我无论如何都无法弄清楚如何设置它,以便我可以测试使用g元素的函数。谢谢!
1个回答

2
这个问题相当古老,但与我遇到的问题最相关,我有一个简单的解决方案。
假设您有一个测试用例的装置,如下所示(请原谅轻微的伪代码):
@pytest.fixture()
def test_client():
    app = create_app()
    with app.test_client() as test_client:
        with app.app_context():
            yield test_client

我尝试创建一个修改g的fixture,def modify_g(test_client)认为它依赖于test_client提供的上下文,这样就可以使用它。由于我可能没有完全理解pytest如何评估fixtures的某些内容,情况并非如此。您将收到相同的'_AppCtxGlobals' object has no attribute错误。但是,如果您创建一个中间函数,则可以正确评估它,并且修改后的g对象将存在于测试上下文中。

@pytest.fixture()
def pre_test_client():
    app = create_app()
    with app.test_client() as test_client:
        with app.app_context():
            yield test_client

@pytest.fixture()
def test_client(pre_test_client):
    yield pre_test_client

@pytest.fixture()
def modify_g(pre_test_client):
    g.user = 'test'

如果定义了g,则使用g进行测试:

def test_g_data(test_client, modify_g):

这意味着在测试函数中将许多不同的g data状态模拟成固定值非常容易。
我承认我不完全理解为什么这是必要的,因此我希望对pytest如何评估fixtures进行任何解释。
请注意,这忽略了Flask提供的appcontext_pushed解决方案,但这是一种相当快速且简单的方法来使其工作,尽管可能不是最佳解决方案。

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