I'm writing a unit test for a view that uses the current logged in user in a query:
@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)
and the test:
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'
and in my settings LOGIN_DISABLED = True
.
My problem is that when running the test current_user is never set.
I've tried logging in using the test client and wrapping my tests in a with TestLogin.client:
but current_user
is just never set. Any ideas on how to set it?
Consider the below sample app I created for this question
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)
There are different ways to testing logged in flows.
Disable Login and @login_required
In this you don't use current_user
in the request call and just protect the flow to an authenticated user. In such case you can use below kind of approach
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
The test will fail in this case as the user will allows to access a authenticated flow. And the current_user
will be set as a Anonymous User. And it is as good as disabling @login_required
.
Testing with actual login
To do this you need to make sure that you can login to your app using POST to the endpoint where you actually login
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
This will even set the current_user
correctly. In my case I didn't take any form data parameters, in your case you will use something like below
self.app.post('/login', data=dict(
username=username,
password=password
), follow_redirects=True)
Using Session Cookies
In this case you set the session user_id
and _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
This will in turn call the
@login_manager.user_loader
def load_user(user_id):
return MyUser()
To get the actual user based on the user_id
provided by us in session 12
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With