mercredi 16 décembre 2020

Flask PyTest test fails when testing an user login after registration

I am having a really weird issue implementing tests for my Flask app. I am using a session scoped test_client to run all my tests. I am implementing tests for user registration and logging in. If I comment out my registration test and execute the login test, the test completes successfully. However, if I run a test_register followed by a test_login, the test fails. Below is my code for the tests

def test_valid_register(client, db):
    response = register(client, db, 'testuser123', 'password', 'password')
    assert response.status_code == 200
    assert db.session.query(User).filter(User.username == 'testuser123').first()
    assert b'Dashboard' in response.data
    logout(client)

def test_valid_login(client, db):
    USERNAME = 'user1'
    PASSWORD = 'pa$$w0rd'
    response = login(client, db, USERNAME, PASSWORD)
    assert response.status_code == 200
    with client.session_transaction(subdomain='test_domain') as session:
        assert session['username'] == USERNAME
        assert session['user_id'] == db.session.query(User).filter( \
        User.username == USERNAME).first().get_id()

    assert b'Dashboard' in response.data

And my utility functions for login and register

def register(client, db, username, password, confirm_password):
    with client.session_transaction(subdomain='test_domain') as session:
        user_entity = db.session.query(User).filter( \
        User.username == username).first()
        if not user_entity and password == confirm_password:
            session['username'] = username
        else:
            session['username'] = None
            session['user_id'] = None
        return client.post(
        '/register', data={
        'username' : username,
        'password' : password,
        'confirm_password' : confirm_password
        },
        follow_redirects=True
        )

def login(client, db, username, password):
    # Simulates a session and sets the session KV pairs accordingly
    with client.session_transaction(subdomain='test_domain') as session:
        user_entity = db.session.query(User).filter( \
        User.username == username).first()
        session['username'] = username if user_entity and user_entity.check_password(password) else None
        session['user_id'] = user_entity.get_id() if user_entity and user_entity.check_password(password) else None
        return client.post(
        '/login', data={
        'username' : username,
        'password' : password
        },
        follow_redirects=True
        )

The program flow is as such - When a user registers a valid account, he will be redirected to a user dashboard page (follow_redirects) with an automatic login and session simulated as shown. In this case, If I exclude the register test and execute the login test only, the test passes. Individually the tests are working fine but when put together it fails.

I have implemented a logging system in my main Flask app that have logged the following messages

DEBUG    app:routes.py:81 Entering login function
DEBUG    app:routes.py:93 Successfully logged in user User ID: 8 -- Username: user1
INFO     app:routes.py:120 Entering dashboard home..                    
WARNING  app:routes.py:122 Anonymous user in dashboard home, going to index.. 

It would seem like the register test have passed successfully and entered the test_valid_login test, in which the user have actually successfully authenticated in line 2 of the log and entered in to the home. However, I do have a check to redirect anonymous users attempting to access my dashboard route back to index which is exactly what is happening right now.

If I execute the valid_login test alone this behavior does not happen. I am not very sure what has gone wrong - previously before I implemented the session simulation the tests were all working fine but I am not very sure if this is causing the tests to fail and why.

Below is my PyTest conftest file -

@pytest.fixture(scope='session')
def app():
    yield flask_app

@pytest.fixture(scope='session')
def client(app):
    # WTF_CSRF_ENABLED = False to allow form submission in tests
    app.config['WTF_CSRF_ENABLED'] = False
    app.config['TESTING'] = True
    return app.test_client()

@pytest.fixture(scope='session')
def db():
    yield ps_db

And this is the dashboard route failing the test -

@app.route('/dashboard', methods=['GET'])
def dashboard():
    logger.info("Entering dashboard home..")
    if current_user.is_anonymous:
        logger.warning("Anonymous user in dashboard home, going to index..")
        return redirect(url_for('index'))

Even though I am not using current_user from flask_login, the login test have passed without much issues until the register test comes in before it.

Any help will be greatly appreciated. Just to clarify, I have a teardown script to remove the newly registered user after each test so the entry into the database will always be valid for registrations.

Aucun commentaire:

Enregistrer un commentaire