Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
430 views
in Technique[技术] by (71.8m points)

python - Testing Flask login and authentication?

I'm developing a Flask application and using Flask-security for user authentication (which in turn uses Flask-login underneath).

I have a route which requires authentication, /user. I'm trying to write a unit test which tests that, for an authenticated user, this returns the appropriate response.

In my unittest I'm creating a user and logging as that user like so:

from unittest import TestCase
from app import app, db
from models import User
from flask_security.utils import login_user

class UserTest(TestCase):
   def setUp(self):
       self.app = app
       self.client = self.app.test_client()
       self._ctx = self.app.test_request_context()
       self._ctx.push()

       db.create_all()

   def tearDown(self):
       if self._ctx is not None:
           self._ctx.pop()

       db.session.remove()
       db.drop_all()

   def test_user_authentication():
       # (the test case is within a test request context)
       user = User(active=True)
       db.session.add(user)
       db.session.commit()
       login_user(user)

       # current_user here is the user
       print(current_user)

       # current_user within this request is an anonymous user
       r = test_client.get('/user')

Within the test current_user returns the correct user. However, the requested view always returns an AnonymousUser as the current_user.

The /user route is defined as:

class CurrentUser(Resource):
    def get(self):
        return current_user  # returns an AnonymousUser

I'm fairly certain I'm just not fully understanding how testing Flask request contexts work. I've read this Flask Request Context documentation a bunch but am still not understanding how to approach this particular unit test.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The problem is different request contexts.

In your normal Flask application, each request creates a new context which will be reused through the whole chain until creating the final response and sending it back to the browser.

When you create and run Flask tests and execute a request (e.g. self.client.post(...)) the context is discarded after receiving the response. Therefore, the current_user is always an AnonymousUser.

To fix this, we have to tell Flask to reuse the same context for the whole test. You can do that by simply wrapping your code with:

with self.client:

You can read more about this topic in the following wonderful article: https://realpython.com/blog/python/python-web-applications-with-flask-part-iii/

Example

Before:

def test_that_something_works():
    response = self.client.post('login', { username: 'James', password: '007' })

    # this will fail, because current_user is an AnonymousUser
    assertEquals(current_user.username, 'James')

After:

def test_that_something_works():
    with self.client:
        response = self.client.post('login', { username: 'James', password: '007' })

        # success
        assertEquals(current_user.username, 'James')

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...