Flask-使用pytest登录

问题描述 投票:0回答:2

我正在尝试制作一个登录到我的烧瓶应用程序的测试套件,但它总是返回一个匿名用户。这是我的代码:

conftest.py:

import pytest
from wahoo_connect import init_app, db
from wahoo_connect.models import User

from dotenv import load_dotenv
load_dotenv('.flaskenv')

@pytest.fixture(scope='module')
def app():
    app = init_app()
    with app.app_context():
        db.create_all()
        user = User(username='testuser', email='[email protected]', forename='Test', surname='User', confirmed=True)
        user.set_password('testing')
        db.session.add(user)
        db.session.commit()
        yield app

@pytest.fixture(scope='module')
def client(app):
    return app.test_client()

测试:

def test_index_page__logged_in(client):
    with client:
        client.post('/auth/login', data=dict(username='testuser', password='testing'), follow_redirects=True)
        assert current_user.username == 'testuser'

和我的登录路线:

@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
    # Login route logic goes here
    if current_user.is_authenticated:
        return redirect(url_for('home_bp.index'))
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()
        if user is None or not user.check_password(form.password.data):
            flash('Invalid username or password', 'warning')
            return redirect(url_for('auth_bp.login'))
        login_user(user, remember=form.remember_me.data)
        next_page = request.args.get('next')
        if not next_page or url_parse(next_page).netloc != '':
            next_page = url_for('home_bp.index')
        return redirect(next_page)
    return render_template('auth/login.html', title='Sign In', form=form)

测试套件比代码更难写!

flask pytest flask-login
2个回答
0
投票

你可以写一个函数来登录

def login(client):
    """Login helper function"""
    return client.post(
        "auth/login",
        data=dict(username='testuser', password='testing'), 
        follow_redirects=True
    )

0
投票

我怀疑您问题的根源是您需要推送请求上下文:将

with client:
替换为
with client.application.test_request_context():
或简单地
app.test_request_context():
.

但是,当您的大多数路由都需要登录用户时,每次需要身份验证时都向登录路由写入

POST
请求是很麻烦的。为了让我们的生活更轻松,我们可以实施官方 Flask 测试教程 中建议的方法的 Flask-Login 版本。请注意,我使用的是 Flask-SQLAlchemy,但没有它也能正常工作。

在我的设置中,

app
夹具不处理数据库设置和拆卸;相反,
client
夹具实现了
db.create_all
db.drop_all
以确保每个测试都有新鲜的
db
实例。在此设置中,每次调用
client
夹具时都不需要在数据库中包含一个测试用户。

基本方法如教程中所述:首先编写一个实现

AuthActions
login
方法的
logout
类。我们使用一个
auth
夹具来请求
client
夹具并返回一个
AuthActions
的实例。测试函数可以请求
auth
夹具并在测试期间根据需要调用
login
logout
方法。

这里是

AuthActions
类和
auth
夹具,它依赖于其他地方定义的
Users
模型。

#conftest.py

import pytest
from app import init_app, db
from app.models import Users

class AuthActions():
    def __init__(self, client, username='TestUser', password='TestPass'):
        self.client = client
        self.username = username
        self.password = password

    def create(self):
        with self.client.application.app_context():
            test_user = Users(username=self.username, password=self.password)
            test_user.save()

    def login(self):
        return self.client.post(
            '/login',
            data={'username': self.username, 'password': self.password}
        )

    def logout(self):
        return self.client.get('/logout')

# Define client and other fixtures here ...

@pytest.fixture
def auth(client):
    return AuthActions(client)

现在让我们测试一个需要认证的路由。请记住,您需要推送请求上下文才能使身份验证工作:

#test_routes.py

def test_secret_route_unauthenticated(client):
    # passes
    with client.application.test_request_context():
        response = client.get('/secret')
        assert response.status_code == 403
        assert not current_user.is_authenticated

def test_secret_route_authenticated(client, auth):
    # passes
    with client.application.test_request_context():
        auth.create_user()
        auth.login()
        response = client.get('/secret')
        assert response.status_code == 200
        assert current_user.is_authenticated

def test_secret_route_authenticated(client, auth):
    # fails; no request context
    auth.create_user()
    auth.login()
    response = client.get('/secret')
    assert response.status_code == 200
    assert current_user.is_authenticated

© www.soinside.com 2019 - 2024. All rights reserved.