How to mock `current_user` in flask templates?

女生的网名这么多〃 提交于 2021-02-18 11:36:54

问题


I want to mock flask-login's current_user under the template rendering. This function return the current logged user.

Right now I'm mocking the AnnonymousUserMixin from flask-login which is returned by default if the user is not authenticated. But this leads to all kind of juggles. If I could simply mock current_user I would be able to create a Mocked object for it to return.

Here a sample of what I'm using today:

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):
        ...                            

Regards,


回答1:


Okay. I found the answer.

flask-login will ask you to initialize a LoginManager instance with login_manager.init_app(your_app). When you do this it add the current_user to your app contexts processors. This happens at flask_login.utils._user_context_processor function, which is defined as

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

Here _get_user is defined at the same module. What I do to mock current_user is mock _get_user at flask_login.utils.

Here is a working example of how it can be done. I am printing the response content so people can see the result differing. A real test would not instantiate Test class by hand and should use unittest.main or something appropriated.

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()

Here is the output of it:

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

Regards,




回答2:


I found this tutorial interesting in the section The Test.

It says this:

current_user needs to be accessed within the context of a request (it is a thread-local object, just like flask.request). When self.client.post completes the request and every thread-local object is torn down. We need to preserve the request context so we can test our integration with Flask-Login. Fortunately, Flask’s test_client is a context manager, which means that we can use it in a with a statement and it will keep the context around as long as we need it:

So in simple words, you can log in your user via post request and the current_user object will be available and then you can test everything you want in the code.

Here is an example:

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())


来源:https://stackoverflow.com/questions/47294304/how-to-mock-current-user-in-flask-templates

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!