[英]Testing Flask-WTF forms that use `FieldList` and `FormField`
I wrote some forms using flask-wtf that use FieldList
and FormField
, and I want to test them using pytest
.我使用 flask-wtf 编写了一些使用FieldList
和FormField
的表单,我想使用pytest
测试它们。 It's a bulk insertion of data from an uploaded CSV这是从上传的 CSV 中批量插入数据
These are my forms:这些是我的表格:
# myapp/admin/forms.py
from wtforms import Form as NoCsrfForm
class SimpleRegistrationForm(NoCsrfForm):
email = StringField('Email')
username = StringField('Username')
password = StringField('Password')
from flask_wtf import FlaskForm
class BulkUserCreationForm(FlaskForm):
users = FieldList(FormField(SimpleRegistrationForm))
submitted = HiddenField()
submit = SubmitField('Register all')
def is_submitted(self):
from flask import request
return super().is_submitted() and 'submitted' in request.form
Note that I'm skipping imports and other stuff.请注意,我正在跳过进口和其他东西。 Also, I used submitted
to stop my @app.route
from passing validate_on_submit()
.另外,我使用submitted
来阻止我的@app.route
通过validate_on_submit()
。
This is a part of my test:这是我测试的一部分:
# a part of a test
# (...) mumble mumble
from myapp.admin.forms import (
BulkUserCreationForm, SimpleRegistrationForm)
usr_form_1 = SimpleRegistrationForm(username="user1",
email="user1@mail.com",
password="pwd1",)
usr_form_2 = SimpleRegistrationForm(username="user2",
email="user2@mail.com",
password="pwd2",)
usr_form_full = BulkUserCreationForm(
users=[usr_form_1, usr_form_2])
# user issues a POST request
rv = client.post(
url_for('bulk-import-users.edit_users')
follow_redirects=True,
data=usr_form_full.data)
assert something_happened()
I'm struggling on how to craft the data
argument of post()
.我正在努力研究如何制作post()
的data
参数。 So far I've read three approaches到目前为止,我已经阅读了三种方法
BulkUserCreationForm.users
该解决方案将数据用作元组,但我不了解元组和表单之间的绑定,例如BulkUserCreationForm.users
This solution relies on usr_form_full.data
of a form instance, which returns a dictionary. 此解决方案依赖于表单实例的usr_form_full.data
,它返回一个字典。 In the mentioned SO answer, it seems to work, but in my case (and for the code I show) I'm getting an error of the form:在提到的 SO 答案中,它似乎有效,但在我的情况下(以及我展示的代码)我收到了以下形式的错误:
/src/venv/lib/python3.6/site-packages/werkzeug/test.py:349: DeprecationWarning: it's no longer possible to pass dicts as `data`. Use tuples or FileStorage objects instead
Googling this error returned this (and not much more).谷歌搜索这个错误返回这个(而不是更多)。 This solution uses hardcoded values, so instead I went for something (I believe) more or less better:该解决方案使用硬编码值,因此我(我相信)或多或少地做了一些更好的事情:
data_full = {field.label.field_id: field.data for form in usr_form_full.users for field in form}
and passed this to the data
attribute.并将其传递给data
属性。 It didn't work.它没有用。 For some reason the rendered .data
attribute does not behave like expected, returning a different repr
(I expected to see the actual value ).由于某种原因,呈现的.data
属性的行为与预期不同,返回了不同的repr
(我希望看到实际值)。
>>> print(data_full)
{'users-0-email': <wtforms.fields.core.StringField object at 0x7f1704f68cc0>, 'users-0-username': <wtforms.fields.core.StringField object at 0x7f1704fa5e10>, 'users-0-password': <wtforms.fields.core.StringField object at 0x7f1704f539e8>, 'users-1-email': <wtforms.fields.core.StringField object at 0x7f1704f26a90>, 'users-1-username': <wtforms.fields.core.StringField object at 0x7f1704f26f98>, 'users-1-password': <wtforms.fields.core.StringField object at 0x7f1704f26828>}
In short, none of the above approaches worked in my test.简而言之,上述方法均未在我的测试中奏效。 What's the right approach?什么是正确的方法? Do I need to pass submit
and submitted
values to my form instance as well?我还需要将submit
和submitted
的值传递给我的表单实例吗?
For anyone who lands here and is trying to pytest the FieldList/FormField combination, which foiled me for much too long, here's how I handled it in my Flask app.对于登陆这里并尝试对 FieldList/FormField 组合进行 pytest 的任何人,这让我很长时间都被挫败了,这里是我在我的 Flask 应用程序中处理它的方式。
I eventually realized that the form information being sent to my code by the POST request could be accessed using request.form
.我最终意识到可以使用request.form
访问通过 POST 请求发送到我的代码的表单信息。 So I put in return request.form
in my endpoint function just after the form was submitted, which let me view what the page was returning as a dictionary.因此,我在提交表单后将return request.form
放入我的端点函数中,这让我可以查看页面作为字典返回的内容。 It looked something like this:它看起来像这样:
{
"my_fields-0-help_text": "test",
"my_fields-1-help_text": "",
"my_fields-2-help_text": ""
}
WTForms takes the name of the field list and attaches a hyphen, a numerical identifier, another hyphen, and the attribute of the FormField. WTForms 采用字段列表的名称并附加一个连字符、一个数字标识符、另一个连字符和 FormField 的属性。
So this is a simplified version of what I needed to test:所以这是我需要测试的简化版本:
class MyFieldForm(FlaskForm):
help_text = TextAreaField()
def __init__(self, field_id=None, field_name=None, *args, **kwargs):
super(MyFieldForm, self).__init__(*args, **kwargs)
self.field_id = field_id
self.field_name = field_name
class MyHelpTextForm(FlaskForm):
my_fields = FieldList(FormField(MyFieldForm))
submit = SubmitField('Submit Changes')
And this is a simplified version of the working test I used:这是我使用的工作测试的简化版本:
def test_page(client):
with client as c:
obj = get_obj(ParentObject) # Function written elsewhere to get the parent object
my_field = get_obj(my_field, obj) # Function written elsewhere to get the child object
assert my_field.parent == obj
assert not my_field.help_text
vals = {
'my_fields-0-help_text': 'help text'
}
response = c.post('path/to/page', data=vals, follow_redirects=True)
assert b'help text' in response.data
assert my_field.help_text == 'help text'
In my case I wanted to test that the parameters passed to my form get passed to a downstream function.在我的例子中,我想测试传递到我的表单的参数是否传递到下游函数。
form = MyForm()
if form.validate_on_submit():
args = unpack_form(form)
do_something(args)
I had the same issue with mocking nested FormField values, so the solution I came up with is to provide a data dictionary where keys are the fields of your form.我在模拟嵌套的 FormField 值时遇到了同样的问题,所以我想出的解决方案是提供一个数据字典,其中键是表单的字段。 If a field is a FormField add a dash between parent field name and nested form field name:如果字段是 FormField,则在父字段名称和嵌套表单字段名称之间添加破折号:
{"parent_form_field-nested_form_field" : "value"}
For example to test this例如测试这个
class ContactDetailsForm(FlaskForm):
phone_number = StringField("Phone number")
email = StringField("Email")
class UserForm(FlaskForm):
name = StringField("Name")
work_contact = FormField(ContactDetailsForm)
home_contact = FormField(ContactDetailsForm)
Write the following mock编写以下模拟
def test_user_form(app):
data = {
"name": "John",
"work_contact-phone_number": "1234",
"work_contact-email": "john@work.com",
"home_contact-phone_number": "5678",
"home_contact-email": "john@home.com"
}
app.post("/user_form", data=data)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.