测试使用FieldField和FormField的Flask-WTF表单

时间:2018-12-21 15:29:21

标签: python testing flask flask-wtforms wtforms

我用flask-wtf编写了一些使用FieldListFormField的表格,我想使用pytest测试它们。这是从上传的CSV批量插入数据

这些是我的表格:

# 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

请注意,我正在跳过导入和其他内容。另外,我使用submitted来阻止@app.route传递validate_on_submit()

这是我测试的一部分

# 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()

我正在努力设计data的{​​{1}}参数。到目前为止,我已经阅读了三种方法

  • This solution使用数据作为元组,但是我不了解post()
  • 之类的元组和表单之间的绑定
  • This solution依赖于表单实例的BulkUserCreationForm.users,该实例返回字典。在提到的SO答案中,它似乎有效,但是在我的情况下(以及我显示的代码),我收到以下形式的错误:

    usr_form_full.data
  • Google搜索此错误returned this(仅此而已)。此解决方案使用了硬编码的值,所以我或多或少地选择了(我认为)更好的东西:

    /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
    

,并将其传递给data_full = {field.label.field_id: field.data for form in usr_form_full.users for field in form} 属性。没用由于某种原因,呈现的data属性的行为与预期不同,返回了不同的.data(我希望看到实际的 value )。

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>} submit值传递给表单实例?

2 个答案:

答案 0 :(得分:0)

在我的例子中,我想测试传递给我的表单的参数是否被传递给了下游函数。

    form = MyForm()
    if form.validate_on_submit():
       args = unpack_form(form)
       do_something(args)

我在模拟嵌套 FormField 值时遇到了同样的问题,所以我想出的解决方案是提供一个数据字典,其中键是表单的字段。如果字段是 FormField,则在父字段名称和嵌套表单字段名称之间添加一个破折号:

{"parent_form_field-nested_form_field" : "value"}

例如测试这个

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)

编写以下模拟

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)

答案 1 :(得分:0)

对于那些登陆这里并试图对 FieldList/FormField 组合进行 pytest 的人来说,这让我失望了太久,这是我在 Flask 应用程序中处理它的方式。

我最终意识到可以使用 request.form 访问通过 POST 请求发送到我的代码的表单信息。因此,我在提交表单后立即将 return request.form 放入我的端点函数中,这让我可以查看页面作为字典返回的内容。它看起来像这样:

{
    "my_fields-0-help_text": "test", 
    "my_fields-1-help_text": "", 
    "my_fields-2-help_text": ""
}

WTForms 使用字段列表的名称并附加一个连字符、一个数字标识符、另一个连字符和 FormField 的属性。

所以这是我需要测试的简化版本:

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')

这是我使用的工作测试的简化版本:

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'