在doctest字符串中嵌入测试代码或数据

时间:2010-07-20 02:49:50

标签: python doctest

我想在文件中分享测试数据和/或函数中的几个doctests。有没有办法在不将它们放在外部文件或被测试文件的代码中的情况下执行此操作?

更新

"""This is the docstring for the module ``fish``.

I've discovered that I can access the module under test
  from within the doctest, and make changes to it, eg


>>> import fish
>>> fish.data = {1: 'red', 2: 'blue'}
"""

def jef():
    """
    Modifications made to the module will persist across subsequent tests:

    >>> import fish
    >>> fish.data[1]
    'red'
    """
    pass

def seuss():
    """
    Although the doctest documentation claims that
      "each time doctest finds a docstring to test,
       it uses a shallow copy of M‘s globals",
      modifications made to the module by a doctest
      are not imported into the context of subsequent docstrings:

    >>> data
    Traceback (most recent call last):
      ...
    NameError: name 'data' is not defined
    """
    pass

所以我猜doctest复制模块一次,然后为每个文档字符串复制副本?

在任何情况下,如果笨拙,将模块导入每个文档字符串似乎都是可用的。

我更喜欢为此使用单独的命名空间,以避免意外践踏实际模块数据,这些数据将以可能未记录的方式导入或不导入后续测试。

我想到,(理论上)可以动态创建模块以包含此命名空间。但是到目前为止,我还没有就the question I asked关于如何做到这一点做任何指示。任何信息都非常受欢迎! (作为对适当问题的回答)

在任何情况下,我都希望将更改直接传播到后续文档字符串的命名空间中。所以我原来的问题仍然存在,以此为限定词。

2 个答案:

答案 0 :(得分:2)

这种情况导致人们不再使用doctests:随着测试的复杂性增加,你需要真正的编程工具才能像设计产品代码一样设计测试。

除了在产品代码中定义共享数据或函数,然后在doctests中使用它们之外,我认为没有办法在doctests中包含共享数据或函数。

您将需要使用真实代码来定义一些测试基础架构。如果您喜欢doctests,可以使用doctests中的基础结构。

答案 1 :(得分:0)

可能,虽然可能没有大声宣传。

要获得具有所有使用共享执行上下文的测试的识字模块(即,单个测试可以共享和重用其结果),必须查看the relevant part of documentation,其中包含:

  

...每次doctest找到要测试的文档字符串时,它都会使用M的全局变量的 副本,这样运行测试不会改变模块的真实全局变量,因此M中的一个测试不会留下意外允许另一个测试工作的面包屑。

     

...

     

您可以强制使用您自己的 dict 作为执行上下文,方法是将globs=your_dict传递给testmod()testfile()

鉴于此,来自doctest模块的I managed to reverse-engineer除了使用副本(即dict' s copy()方法)之外,它还会清除全局字典(在每次测试后使用clear())。

因此,可以使用以下内容修补自己的全局字典:

class Context(dict):
    def clear(self):
        pass
    def copy(self):
        return self 

然后将其用作:

import doctest
from importlib import import_module

module = import_module('some.module')
doctest.testmod(module,
                # Make a copy of globals so tests in this
                # module don't affect the tests in another
                glob=Context(module.__dict__.copy()))