我正在尝试制作一个登录到我的烧瓶应用程序的测试套件,但它总是返回一个匿名用户。这是我的代码:
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)
测试套件比代码更难写!
你可以写一个函数来登录
def login(client):
"""Login helper function"""
return client.post(
"auth/login",
data=dict(username='testuser', password='testing'),
follow_redirects=True
)
我怀疑您问题的根源是您需要推送请求上下文:将
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