【问题标题】:How to set current_user for pytest?如何为 pytest 设置 current_user?
【发布时间】:2018-03-22 01:43:50
【问题描述】:

我正在为在查询中使用当前登录用户的视图编写单元测试:

@app.route('/vendors/create', methods=['GET', 'POST'])
@login_required
def create_vendors():
    vendor_form = VendorForm(request.form)
    if vendor_form.validate_on_submit():
        vendor = db.session.query(Vendors).filter(Vendors.name == vendor_form.name.data,
                                                  Vendors.users.contains(g.user)).first()
        if vendor:
            flash('There is a vendor with this name already.')
            return redirect(url_for('create_vendors', vendor_form=vendor_form))
        vendor = Vendors(name=vendor_form.name.data, aws_access_key=vendor_form.aws_access_key.data,
                         merchant_key=vendor_form.merchant_key.data, secret_key=vendor_form.secret_key.data)
        vendor.users.append(current_user)
        db.session.add(vendor)
        db.session.commit()
        return redirect(url_for('vendors'))
    return render_template('edit_vendor.html', vendor_form=vendor_form)

和测试:

def test_create_vendor(self):
    response = TestViews.client.post('/vendors/create', follow_redirects=True,
                                     data=dict(name='Name', aws_access_key='aws_access_key',
                                               merchant_key='merchant_key',
                                               secret_key='secret_key'))
    assert response.status_code == 200
    vendors = db.session.query(Vendors).filter(Vendors.aws_access_key == 'aws_access_key').all()
    assert len(vendors) == 1
    assert vendors[0].name == 'Name'

在我的设置中LOGIN_DISABLED = True

我的问题是,在运行测试时,current_user 从未设置。

我尝试使用测试客户端登录并将我的测试包装在 with TestLogin.client: 中,但 current_user 从未设置过。关于如何设置它的任何想法?

【问题讨论】:

  • 您是否在设置中致电login_user (flask_security.utils)?你也可以试试with self.client:
  • 是的,这些都不起作用。
  • self.client.post(...) 代替TestViews.client.post(...) 怎么样
  • 试过了,没有运气。

标签: python flask flask-login


【解决方案1】:

考虑一下我为这个问题创建的以下示例应用程序

from flask import Flask, request,
from flask_login import LoginManager
from flask_login.utils import login_required, current_user, login_user

app = Flask(__name__)
app.secret_key = 'super secret key'
app.config['SESSION_TYPE'] = 'filesystem'

login_manager = LoginManager()
login_manager.init_app(app)

class MyUser():
    name = "tarun"

    def is_authenticated(self):
        return True

    def is_active(self):
        return True

    def is_anonymous(self):
        return False

    def get_id(self):
        return 10


@login_manager.user_loader
def load_user(user_id):
    return MyUser()

@app.route("/login", methods=["POST"])
def login():
    login_user(MyUser())
    return "Authenticated"

@app.route("/", methods=["GET", "POST"])
@login_required
def index():
    return "Authenticated " # + current_user


if __name__ == "__main__":
    app.run(debug=True)

有不同的方法来测试登录的流程。

禁用登录和@login_required

在这种情况下,您不会在请求调用中使用current_user,而只是保护流向经过身份验证的用户。在这种情况下,您可以使用以下方法

import flasktest as flaskr

class FlaskrTestCase(unittest.TestCase):

    def setUp(self):
        flaskr.app.testing = True
        flaskr.app.config['LOGIN_DISABLED'] = True
        flaskr.app.login_manager.init_app(flaskr.app)
        self.app = flaskr.app.test_client()

    def test_without_login(self):
        res = self.app.post("/")

        assert "Unauthorized" in res.data

在这种情况下,测试将失败,因为用户将允许访问经过身份验证的流。 current_user 将被设置为匿名用户。就像禁用@login_required一样好。

使用实际登录进行测试

为此,您需要确保您可以使用 POST 到您实际登录的端点登录到您的应用

import unittest

import flasktest as flaskr

class FlaskrTestCase(unittest.TestCase):

    def setUp(self):
        flaskr.app.testing = True
        self.app = flaskr.app.test_client()

    def tearDown(self):
        pass

    def test_login(self):
        self.app.post("/login")

        res = self.app.get("/")

        assert "Authenticated" in res.data

    def test_without_login(self):
        res = self.app.post("/")

        assert "Unauthorized" in res.data

这甚至可以正确设置current_user。就我而言,我没有采用任何表单数据参数,在您的情况下,您将使用如下所示的内容

self.app.post('/login', data=dict(
        username=username,
        password=password
    ), follow_redirects=True)

使用会话 Cookie

在这种情况下,您设置会话 user_id_fresh

def test_login_session(self):
    with self.app.session_transaction() as sess:
        sess['user_id'] = '12'
        sess['_fresh'] = True  # https://flask-login.readthedocs.org/en/latest/#fresh-logins

    res = self.app.get("/")

    assert "Authenticated" in res.data

这将反过来调用

@login_manager.user_loader
def load_user(user_id):
    return MyUser()

根据我们在会话12中提供的user_id获取实际用户

【讨论】:

  • 不确定这是否代表我的问题。
  • @ruipacheco 我认为这个答案可以解决您的问题,请您解释一下为什么这不能解决您的问题。
  • 我已经尝试了他显示的所有内容,但在我运行单元测试时,我的视图中仍然没有 current_user。不依赖于 current_user 的视图可以正常工作。
  • @ruipacheco,我在发布之前测试了每一个代码,所以我不确定你是否正确使用它。可以用最少的代码共享 git repo 来重现问题吗?
  • 我怀疑这可能确实在我身边。很遗憾,我无法分享代码。
【解决方案2】:

简单地模拟 flask_login.current_user 并设置一个固定的返回值,如 'testuser'

【讨论】:

  • 简单地模拟太模糊了。您能否分享一个模拟 current_user 的示例?
猜你喜欢
  • 2021-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-27
  • 2023-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多