Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock `current_user` in flask templates?

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,

like image 801
geckos Avatar asked Feb 04 '23 03:02

geckos


1 Answers

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,

like image 141
geckos Avatar answered Feb 12 '23 22:02

geckos