对 Dockerized Flask 应用程序进行单元测试时出现断言错误(200 次成功!= 400 次错误请求)
Assertion Error (200 Success != 400 Bad Request) while unit testing a Dockerized Flask App
好的,我已经为这个问题苦苦挣扎了 2 天了。当我在浏览器中手动 posting 表单中的数据时,一切正常,我收到了应该显示 'Thanks...' 的闪现消息。在测试我的 Flask 应用程序时,此测试未通过,因为在我的 Flask 表单上发送 post 请求时收到 400 Bad Request 错误。明确地说,我正在使用 Flask-Mail 和 WTForms 作为表单,我的应用程序是 dockerized 的,还有 运行 redis 和 celery。我对这些东西有点陌生,所以如果我的问题不够清楚,请告诉我是否应该提供更详细的信息。谢谢,这里是相关代码和使用 py.test 测试时显示的错误。对链接感到抱歉,我仍然不允许在 Whosebug 上 post 图片。
错误代码:
Pytest Assertion Error
contact/forms.py:
from flask_wtf import FlaskForm
from wtforms import TextAreaField, StringField
from wtforms.validators import DataRequired, Length, Email
class ContactForm(FlaskForm):
email = StringField("What's your e-mail address?",
[Email(), DataRequired(), Length(3, 254)])
message = TextAreaField("What's your question or issue?",
[DataRequired(), Length(1, 8192)])
contact/views.py:
from flask import (
Blueprint,
flash,
redirect,
request,
url_for,
render_template)
from flexio.blueprints.contact.forms import ContactForm
contact = Blueprint('contact', __name__, template_folder='templates')
@contact.route('/contact', methods=['GET', 'POST'])
def index():
form = ContactForm()
if form.validate_on_submit():
# This prevents circular imports.
from flexio.blueprints.contact.tasks import deliver_contact_email
deliver_contact_email(request.form.get('email'),
request.form.get('message'))
flash('Thanks, expect a response shortly.', 'success')
return redirect(url_for('contact.index'))
return render_template('contact/index.html', form=form)
contact/tasks.py:
from lib.flask_mailplus import send_template_message
from flexio.app import create_celery_app
celery = create_celery_app()
@celery.task()
def deliver_contact_email(email, message):
"""
Send a contact e-mail.
:param email: E-mail address of the visitor
:type user_id: str
:param message: E-mail message
:type user_id: str
:return: None
"""
ctx = {'email': email, 'message': message}
send_template_message(subject='[Flexio] Contact',
sender=email,
recipients=[celery.conf.get('MAIL_USERNAME')],
reply_to=email,
template='contact/mail/index', ctx=ctx)
return None
lib/tests.py:
def assert_status_with_message(status_code=200, response=None, message=None):
"""
Check to see if a message is contained within a response.
:param status_code: Status code that defaults to 200
:type status_code: int
:param response: Flask response
:type response: str
:param message: String to check for
:type message: str
:return: None
"""
assert response.status_code == status_code
assert message in str(response.data)
tests/contact/test_views.py:
from flask import url_for
from lib.tests import assert_status_with_message
class TestContact(object):
def test_contact_page(self, client):
""" Contact page should respond with a success 200. """
response = client.get(url_for('contact.index'))
assert response.status_code == 200
def test_contact_form(self, client):
""" Contact form should redirect with a message. """
form = {
'email': 'foo@bar.com',
'message': 'Test message from Flexio.'
}
response = client.post(url_for('contact.index'), data=form,
follow_redirects=True)
assert_status_with_message(200, response, 'Thanks')
您的浏览器将通过 GET
请求 首先 请求表单,因此已将 CSRF token 作为 cookie 和隐藏表单中的表单元素。当您提交表单时,CSRF 保护通过。
您的测试没有发出 GET
请求,也没有使用此类请求发出的表单中的表单字段,因此您的 POST
请求缺少 cookie 和隐藏的领域。
在测试中,您可以通过将 WTF_CSRF_ENABLED
参数设置为 False
:
来禁用 CSRF 保护
app.config['WTF_CSRF_ENABLED'] = False
好的,我已经为这个问题苦苦挣扎了 2 天了。当我在浏览器中手动 posting 表单中的数据时,一切正常,我收到了应该显示 'Thanks...' 的闪现消息。在测试我的 Flask 应用程序时,此测试未通过,因为在我的 Flask 表单上发送 post 请求时收到 400 Bad Request 错误。明确地说,我正在使用 Flask-Mail 和 WTForms 作为表单,我的应用程序是 dockerized 的,还有 运行 redis 和 celery。我对这些东西有点陌生,所以如果我的问题不够清楚,请告诉我是否应该提供更详细的信息。谢谢,这里是相关代码和使用 py.test 测试时显示的错误。对链接感到抱歉,我仍然不允许在 Whosebug 上 post 图片。
错误代码: Pytest Assertion Error
contact/forms.py:
from flask_wtf import FlaskForm
from wtforms import TextAreaField, StringField
from wtforms.validators import DataRequired, Length, Email
class ContactForm(FlaskForm):
email = StringField("What's your e-mail address?",
[Email(), DataRequired(), Length(3, 254)])
message = TextAreaField("What's your question or issue?",
[DataRequired(), Length(1, 8192)])
contact/views.py:
from flask import (
Blueprint,
flash,
redirect,
request,
url_for,
render_template)
from flexio.blueprints.contact.forms import ContactForm
contact = Blueprint('contact', __name__, template_folder='templates')
@contact.route('/contact', methods=['GET', 'POST'])
def index():
form = ContactForm()
if form.validate_on_submit():
# This prevents circular imports.
from flexio.blueprints.contact.tasks import deliver_contact_email
deliver_contact_email(request.form.get('email'),
request.form.get('message'))
flash('Thanks, expect a response shortly.', 'success')
return redirect(url_for('contact.index'))
return render_template('contact/index.html', form=form)
contact/tasks.py:
from lib.flask_mailplus import send_template_message
from flexio.app import create_celery_app
celery = create_celery_app()
@celery.task()
def deliver_contact_email(email, message):
"""
Send a contact e-mail.
:param email: E-mail address of the visitor
:type user_id: str
:param message: E-mail message
:type user_id: str
:return: None
"""
ctx = {'email': email, 'message': message}
send_template_message(subject='[Flexio] Contact',
sender=email,
recipients=[celery.conf.get('MAIL_USERNAME')],
reply_to=email,
template='contact/mail/index', ctx=ctx)
return None
lib/tests.py:
def assert_status_with_message(status_code=200, response=None, message=None):
"""
Check to see if a message is contained within a response.
:param status_code: Status code that defaults to 200
:type status_code: int
:param response: Flask response
:type response: str
:param message: String to check for
:type message: str
:return: None
"""
assert response.status_code == status_code
assert message in str(response.data)
tests/contact/test_views.py:
from flask import url_for
from lib.tests import assert_status_with_message
class TestContact(object):
def test_contact_page(self, client):
""" Contact page should respond with a success 200. """
response = client.get(url_for('contact.index'))
assert response.status_code == 200
def test_contact_form(self, client):
""" Contact form should redirect with a message. """
form = {
'email': 'foo@bar.com',
'message': 'Test message from Flexio.'
}
response = client.post(url_for('contact.index'), data=form,
follow_redirects=True)
assert_status_with_message(200, response, 'Thanks')
您的浏览器将通过 GET
请求 首先 请求表单,因此已将 CSRF token 作为 cookie 和隐藏表单中的表单元素。当您提交表单时,CSRF 保护通过。
您的测试没有发出 GET
请求,也没有使用此类请求发出的表单中的表单字段,因此您的 POST
请求缺少 cookie 和隐藏的领域。
在测试中,您可以通过将 WTF_CSRF_ENABLED
参数设置为 False
:
app.config['WTF_CSRF_ENABLED'] = False