【问题标题】:flask pytest test function that uses g使用 g 的烧瓶 pytest 测试函数
【发布时间】:2017-08-15 07:36:18
【问题描述】:

我正在使用Flask Cookiecutter 构建我的测试,并且我的所有其他测试都运行良好。当我测试一个使用g 元素的函数时,我只会遇到问题,例如我的views.py 文件中的g.user

我的conftest.py 与flask-cookiecutter 完全相同,加上来自Flask-Testing 的the faking resources and context trick

### 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,但我一生都无法弄清楚如何设置它,所以我可以测试使用@的函数987654331@ 元素。谢谢!

【问题讨论】:

    标签: python-3.x flask pytest


    【解决方案1】:

    这个问题很老了,但与我遇到的问题最相关,我有一个简单的解决方案。

    为测试客户端提供这样的夹具(请原谅轻微的伪代码):

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

    我尝试创建一个修改 g 的夹具,def modify_g(test_client) 认为依赖于 test_client 提供的上下文将使其可用。由于我可能不完全了解 pytest 如何评估固定装置,因此情况并非如此。您会得到相同的 '_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 的测试将起作用:

    def test_g_data(test_client, modify_g):
    

    这意味着在 g 数据中模拟许多不同的状态并将它们作为夹具放入测试函数中非常容易。

    我承认我不明白为什么这是必要的,所以我希望能解释一下 pytest 如何评估夹具。

    请注意,这忽略了 Flask 提供的 appcontext_pushed 解决方案,但它是一种非常快速和简单的方法来使其工作,尽管可能不是最佳解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-30
      相关资源
      最近更新 更多