在doctest中,有没有办法将yaml代码块视为变量?

问题描述

我正在使用doctest测试.rst文件中的代码段。在许多情况下,最重要的测试是对yaml配置的简单有效性检查。

例如:

>>> my_yaml = """
... foo:
...   bar:
...    - baz1
...    - baz2
... """
>>> my_yaml_dict = yaml.load(my_yaml_string,Loader=yaml.FullLoader)
>>> assert "baz_2" in my_yaml_dict["foo"]["bar"]

为了使代码更具可读性和可粘贴性,我只想显示yaml块,并将测试本身放在隐藏的代码块中。

这有效:

>>> my_yaml = """
... foo:
...   bar:
...    - baz1
...    - baz2
... """

.. invisible-code-block: python

    >>> my_yaml_dict = yaml.load(my_yaml_string,Loader=yaml.FullLoader)
    >>> assert "baz_2" in my_yaml_dict["foo"]["bar"]

但是,yaml块仍封装在my_yaml="""..."""中,这使得复制粘贴变得很困难。

是否有一种方法可以将代码块本身视为变量?我正在按照以下思路进行构想:

.. code-block:: yaml # doctest: +varname=my_yaml_string

    foo:
      bar:
       - baz1
       - baz2

.. invisible-code-block: python

    >>> my_yaml_dict = yaml.load(my_yaml_string,Loader=yaml.FullLoader)
    >>> assert "baz_2" in my_yaml_dict["foo"]["bar"]

解决方法

根据文档,我认为不可以更改/跳过文档字符串定界符(>>> ... ):

任何期望的输出必须立即跟随包含代码的最后'>>>'或'...'行,并且期望的输出(如果有的话)扩展到下一个'>>>'或全空白行。 https://docs.python.org/3/library/doctest.html#how-are-docstring-examples-recognized

另一种解决方案是将Yaml数据移动到外部变量,该变量在doctest块中未定义:

my_yaml_string = """
foo:
    bar:
      - baz1
      - baz2
"""

然后可以直接在doctest块中使用上述变量:

>>> my_yaml_dict = yaml.load(my_yaml_string,Loader=yaml.FullLoader)
>>> assert "baz_2" in my_yaml_dict["foo"]["bar"]

另外,可以在另一个模块中定义my_yaml_string变量,以不影响运行时性能:

>>> import test_constants
>>> my_yaml_dict = yaml.load(test_constants.my_yaml_string,Loader=yaml.FullLoader)
>>> assert "baz_2" in my_yaml_dict["foo"]["bar"]

此外,测试数据可以完全移动到单独的文件中。这样做还有一个好处,就是可以为所选的数据序列化语言(在本例中为Yaml)启用静态分析器覆盖范围:

# test_data.yaml
foo:
    bar:
      - baz1
      - baz2
>>> my_yaml_dict = yaml.load(open("test_data.yaml"),Loader=yaml.FullLoader)
>>> assert "baz_2" in my_yaml_dict["foo"]["bar"]

请注意,"test_data.yaml"可能需要转换为绝对路径,这取决于doctest的执行方式。