如何在烧瓶模板中模拟`current_user`?

Posted

技术标签:

【中文标题】如何在烧瓶模板中模拟`current_user`?【英文标题】:How to mock `current_user` in flask templates? 【发布时间】:2018-04-27 21:42:38 【问题描述】:

我想在模板渲染下模拟flask-logincurrent_user。该函数返回当前登录的用户。

现在我正在模拟来自flask-loginAnnonymousUserMixin,如果用户未通过身份验证,则默认返回。但这会导致各种杂耍。如果我可以简单地模拟current_user,我将能够创建一个模拟对象让它返回。

这是我今天使用的示例:

import unnittest
from flask_login.mixins import AnonymousUserMixin


class TestFoo(unittest.TestCase):
    @patch.object(AnonymousUserMixin, 'is_admin', create=True,                  
                  return_value=False)                                           
    @patch.object(AnonymousUserMixin, 'is_authenticated',  return_value=True)                                           
    def test_user_restriction(self, *args):
        ...                            

问候,

【问题讨论】:

【参考方案1】:

好的。我找到了答案。

flask-login 会要求你用login_manager.init_app(your_app) 初始化一个LoginManager 实例。当你这样做时,它会将current_user 添加到你的应用上下文处理器中。这发生在flask_login.utils._user_context_processor 函数,它被定义为

def _user_context_processor():
    return dict(current_user=_get_user())

这里_get_user 是在同一个模块中定义的。我模拟current_user 的方法是在flask_login.utils 模拟_get_user

这是一个如何完成的工作示例。我正在打印响应内容,以便人们可以看到不同的结果。真正的测试不会手动实例化 Test 类,应该使用 unittest.main 或其他适当的东西。

from flask import Flask, render_template_string as render_string
from flask_login import LoginManager, UserMixin

app = Flask(__name__)
loginmgr = LoginManager(app)
loginmgr.init_app(app)


class User(UserMixin):
    pass


@loginmgr.user_loader
def load_user(user_id):
    return User.get(user_id)


@app.route('/')
def index():
    return render_string('Hello,  current_user | safe ')


if __name__ == '__main__':
    import unittest
    from unittest import mock

    class Test:
        def test(self):
            client = app.test_client()
            response = client.get('/')
            data = response.data.decode('utf-8')
            print(data)

        @mock.patch('flask_login.utils._get_user')
        def test_current_user(self, current_user):
            user = mock.MagicMock() 
            user.__repr__ = lambda self: 'Mr Mocked'
            current_user.return_value = user
            client = app.test_client()
            response = client.get('/')
            data = response.data.decode('utf-8')
            print(data)


    t = Test()
    t.test()
    t.test_current_user()

这是它的输出:

Hello, <flask_login.mixins.AnonymousUserMixin object at 0x7f9d5ddaaf60>
Hello, Mr Mocked

问候,

【讨论】:

我们如何模拟 current_user 以获得 current_user.id = 1 和 current_user.role.name = 'Admin'? 试试这个current_user.return_value.id = 1current_user.return_value.role.return_value.name = 'Admin' 我已经尝试过了,但 current_user.role.name 实际上是模拟对象 - 而不是 'Admin' . 试试.name.return_value = 'Admin' 对不起,但问题是我使用flask login_user() 登录用户,我只需要使用你的@mock.patch('flask_login.utils._get_user') 来获取当前用户没有为 current_user 定义模拟对象。【参考方案2】:

我在测试部分发现这个tutorial很有趣。

上面写着:

current_user 需要在请求的上下文中被访问(它 是一个线程本地对象,就像 flask.request 一样)。什么时候 self.client.post 完成请求和每个线程本地对象 被拆除。我们需要保留请求上下文以便我们可以测试 我们与 Flask-Login 的集成。幸运的是,Flask 的 test_client 是 上下文管理器,这意味着我们可以在 with 语句中使用它 只要我们需要,它就会一直保留上下文:

简单来说,您可以通过 post 请求登录您的用户,current_user 对象将可用,然后您可以在代码中测试您想要的所有内容。

这是一个例子:

with self.client:
    response = self.client.post(url_for('users.login'),
                                data='email': 'joe@joes.com', 'password': '12345')

    self.assert_redirects(response, url_for('index'))
    self.assertTrue(current_user.name == 'Joe')
    self.assertFalse(current_user.is_anonymous())

【讨论】:

这很好,但我登录到 LDAP,我不想依赖 LDAP 进行单元测试。 LDAP 是什么意思? LDAP 是一种用户服务器。用于保持用户、凭据的所有排序。

以上是关于如何在烧瓶模板中模拟`current_user`?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 current_user 没有在烧瓶登录中进行身份验证?

如何动态选择要在烧瓶中使用的模板目录?

如何使用 Jinja2 模板在烧瓶中解码 &#39 [重复]

如何在python烧瓶中获取具有本地时区的模板文件的修改日期

如何将数据从烧瓶发送到 html 模板

如何正确继承烧瓶中使用引导程序的模板?