【问题标题】:Testing a Wagtail StructBlock with a StreamBlockField使用 StreamBlockField 测试 Wagtail StructBlock
【发布时间】:2021-12-29 13:22:12
【问题描述】:

我正在尝试在 StructBlock 上运行一些单元测试,它由普通块字段和 StreamBlock 组成。

我遇到的问题是我可以构建一个渲染块的测试,但我无法测试 StreamBlock 验证(即,我无法测试块的clean()

堆栈

  • Python 3.9.6
  • Django 3.2
  • 鹡鸰 2.13
  • pytest 6.2
  • pytest-django 4.4

块定义

MyStructBlock

    class MyStructBlock(blocks.StructBlock):
        image = ImageChooserBlock()

        heading = blocks.CharBlock(required=True)
        description = blocks.RichTextBlock(features=["bold", "italic"])
        links = blocks.StreamBlock([("link", LinkBlock())], icon="link", min_num=1, max_num=6)

        class Meta:
            icon = "list-ul"
            template = "blocks/two_column_with_link_list_block.html"

链接块

    class LinkBlock(blocks.StructBlock):
        link_text = blocks.CharBlock()
        internal_link = blocks.PageChooserBlock()
        internal_document = DocumentChooserBlock()
        external_link = blocks.URLBlock()

通过这个设置,我创建了这种block_definition

{
   'image': <Image: Thumbnail of subject>, 
   'heading': 'SomeText', 
   'description': 'Hello, Son', 
   'links':  
     [
       {'value': 
         {
          'link_text': 'Walk trip thought region.', 
          'internal_link': None, 
          'document_link': None, 
          'external_link': 'www.example.com'
         }
       },
       {'value': {...}},
       {'value': {...}},
      ]
}

那么这样的测试就可以正常工作了:

   def test_structure():
      my_struct_block = MyStructBlock()
      block_def = block_definition
      rendered_block_html = BeautifulSoup(my_struct_block.render(value=block_def)))
      assert <<THINGS ABOUT THE STRUCTURE>>

块渲染,一切都很好,但是当我尝试clean块时,一切都开始横向移动。

   def test_validation():
       my_struct_block = MyStructBlock()
       block_def = block_definition
       rendered_block_html = BeautifulSoup(my_struct_block.render(my_struct_block.clean(block_def)))

会产生这样的结果:

self = <wagtail.core.blocks.field_block.RichTextBlock object at 0x7f874f430580>, value = 'Hello, Son'

    def value_for_form(self, value):
        # Rich text editors take the source-HTML string as input (and takes care
        # of expanding it for the purposes of the editor)
>       return value.source
E       AttributeError: 'str' object has no attribute 'source'

.direnv/python-3.9.6/lib/python3.9/site-packages/wagtail/core/blocks/field_block.py:602: AttributeError

哪个描述性足够——我知道它需要一个 Richtext Block 定义——但为什么会有区别?

注意:我尝试使用RichTextblock_definition 定义为期望RichText 的字段的值,但失败了。如果我删除 RichText 字段,则清理将在我用来定义 LinkBlockdicts 上失败。

问题

是否有一种规范的方法来设置这样的测试来处理复杂的块,以便块定义的公共来源可以测试render 以及cleanrender?或者,这种类型的块在某种程度上是否需要一种集成方法,在该方法中我构建一个页面,其中添加了复杂的块为stream_data,然后请求该页面并使用响应的呈现?

【问题讨论】:

    标签: testing wagtail


    【解决方案1】:

    每个块类型都有一个对应的“本机”数据类型,用于它期望使用的数据 - 对于更简单的块,这种数据类型就是您所期望的(例如,CharBlock 的字符串,ImageChooserBlock 的 Image 实例)但是对于一些更复杂的,定义了一个自定义类型:

    • 对于 RichTextBlock,本机类型为 wagtail.core.rich_text.RichText(其行为类似于字符串,但也具有 source 属性,例如页面链接中的页面 ID 保持不变)
    • 对于 StreamBlock,本机类型是 wagtail.core.blocks.StreamValue(一种序列类型,其中每个项目都是具有 block_typevalue 属性的 StreamValue)。

    render 方法通常会在您使用错误类型(例如 RichTextBlock 的字符串或 StreamBlock 的字典列表)时非常宽容,因为它实际上只是在调用您自己的模板代码。 clean 方法会更加挑剔,因为它运行的是特定于每个块的 Python 逻辑。

    不幸的是,每个块使用的正确类型并没有真正正式记录,其中一些构建起来非常繁琐(例如,需要将 StructValue 传递给相应 StructBlock 的引用)——在测试代码之外,有不需要从头开始创建这些对象,因为数据通常来自某些外部来源(例如表单提交或数据库),并且每个块将负责将其转换为其本机类型。

    考虑到这一点,我建议您通过搭载 to_python 方法来构建数据,该方法将 JSON 表示转换为存储在数据库中(仅包含简单的 Python 数据类型 - 整数、字符串、列表, dicts) 转化为原生数据类型:

    block_def = my_struct_block.to_python({
       'image': 123,  # the image ID
       'heading': 'SomeText', 
       'description': 'Hello, Son', 
       'links':  
         [
           {'type': 'link', 'value': 
             {
              'link_text': 'Walk trip thought region.', 
              'internal_link': None, 
              'document_link': None, 
              'external_link': 'www.example.com'
             }
           },
           {'type': 'link', 'value': {...}},
           {'type': 'link', 'value': {...}},
          ]
    })
    

    my_struct_block.clean(block_def) 有望成功。

    【讨论】:

    • 效果很好,谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-26
    • 2020-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多