我目前正在使用Pytest测试我的Flask应用程序,并遇到POST请求和重定向的问题。让我解释一下。
用户想要注册我们的新站点,但必须确认他们拥有其他站点的帐户。一旦他们确认了另一个帐户的凭证,便将其带到注册页面。如果他们来自确认页面,他们只能只能点击注册页面,否则他们将被重定向回首页。
我想测试此功能,并且可以成功向确认页面发出POST请求。如果我未指定follow_redirects=True
并打印响应数据,则会得到以下HTML:
Redirecting...Redirecting...
You should be redirected automatically to target URL: /register?emp_id=1. If not click the link.
太好了!正是我想要的!我想重定向到注册页面。
现在,当我确实指定follow_redirects=True
并打印出响应数据时,我希望返回注册页面HTML。相反,响应数据返回主页HTML。
我进一步调查了问题所在。正如我之前提到的,仅方式可用于进入注册页面,即来自确认页面。在测试期间,我查看了视图中的request.referrer
属性,它将返回None
。我尝试在测试的POST请求中设置Referrer
标头内容,但没有成功。
这是我正在使用的代码:
views.py
@app.route('/confirm', methods=['GET', 'POST'])
def confirm_bpm():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = BPMLoginForm()
if form.validate_on_submit():
bpm_user = BPMUser.query\
.filter(and_(BPMUser.group_name == form.group_name.data,
BPMUser.user_name == form.username.data,
BPMUser.password == encrypt(form.password.data)))\
.first()
if not bpm_user:
flash('BPM user account does not exist!')
url = url_for('confirm_bpm')
return redirect(url)
if bpm_user.user_level != 3:
flash('Only L3 Users can register through this portal.')
url = url_for('confirm_bpm')
return redirect(url)
url = url_for('register', emp_id=bpm_user.emp_id)
return redirect(url)
return render_template('login/confirm_bpm.html', form=form)
@app.route('/register', methods=['GET', 'POST'])
def register():
if current_user.is_authenticated:
return redirect(url_for('index'))
if request.method == 'GET' and\
request.referrer != request.url_root + 'confirm':
return redirect(url_for('index'))
emp_id = request.args.get('emp_id')
emp_id_exists = User.query.filter_by(emp_id=emp_id).first()
if emp_id_exists:
flash('User is already registered!')
return redirect(url_for('login'))
form = RegistrationForm()
if form.validate_on_submit():
new_user = User(login_type=form.login_type.data, login=form.login.data,
emp_id=emp_id)
new_user.set_password(form.password.data)
db.session.add(new_user)
db.session.commit()
flash('Registration successful!')
return redirect(url_for('login'))
return render_template('login/register.html', form=form)
base.py
from config import TestConfig
from app import app, db
@pytest.fixture
def client():
"""
Initializes test requests for each individual test. The test request
keeps track of cookies.
"""
app.config.from_object(TestConfig)
client = app.test_client()
ctx = app.app_context()
ctx.push()
yield client
ctx.pop()
def confirm_bpm_login(client, group_name, username, password):
"""
POST to /confirm
"""
return client.post('/confirm', data=dict(
group_name=group_name,
username=username,
password=password,
submit=True
), follow_redirects=True)
test_auth.py
from app import db
from app.models import BPMCompany, BPMEmployee, User, BPMUser
from tests.base import client, db_data, login, confirm_bpm_login
def test_registration_page_from_confirm(client, db_data):
"""
Test registration page by HTTP GET request from "/confirm" url.
Should cause redirect to registration page.
!!! FAILING !!!
Reason: The POST to /confirm will redirect us to /register?emp_id=1,
but it will return the index.html because in the register view,
request.referrer does not recognize the POST is coming from /confirm_bpm
"""
bpm_user = BPMUser.query.filter_by(id=1).first()
rv = confirm_bpm_login(client, bpm_user.group_name,
bpm_user.user_name, 'jsmith01')
assert b'Register' in rv.data
db_data
参数是 base.py 中的一个固定装置,它仅使用必要的数据填充数据库,以使注册流程正常工作。
我的目标是测试完整的注册流程,而不必将确认和注册分为两个测试。
答案 0 :(得分:2)
在重定向之后,Flask测试客户端似乎没有添加Referer
标头。
您可以做的是实现您自己的以下重定向版本。也许是这样的:
def confirm_bpm_login(client, group_name, username, password):
"""
POST to /confirm
"""
response = client.post('/confirm', data=dict(
group_name=group_name,
username=username,
password=password,
submit=True
), follow_redirects=False)
if 300 <= response.status_code < 400:
response = client.get(response.headers['Location'], headers={
"Referer": 'http://localhost/confirm'
})
return response
请测试一下,我是从内存中写出来的,可能需要进行一些细微的调整。