【问题标题】:Testing Flask-WTF forms that use `FieldList` and `FormField`测试使用 `FieldList` 和 `FormField` 的 Flask-WTF 表单
【发布时间】:2019-05-22 01:46:32
【问题描述】:

我使用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()

我正在努力研究如何制作 post()data 参数。到目前为止,我已经阅读了三种方法

  • This solution 使用数据作为元组,但我不了解元组和表单之间的绑定,例如 BulkUserCreationForm.users
  • This solution 依赖于表单实例的usr_form_full.data,它返回一个字典。在提到的 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
    
  • 谷歌搜索此错误returned this(仅此而已)。这个解决方案使用硬编码值,所以我选择了一些(我相信)或多或少更好的东西:

    data_full = {field.label.field_id: field.data
                 for form in usr_form_full.users
                 for field in form}
    

并将其传递给data 属性。它没有用。由于某种原因,呈现的.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>}

简而言之,以上方法在我的测试中均无效。什么是正确的方法?我还需要将submitsubmitted 值传递给我的表单实例吗?

【问题讨论】:

    标签: python testing flask flask-wtforms wtforms


    【解决方案1】:

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

        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)
    

    【讨论】:

      【解决方案2】:

      对于登陆这里并试图对 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'
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-01
        • 2012-01-28
        • 2018-12-18
        相关资源
        最近更新 更多