如何使用doctest测试嵌套/重新引发的异常?

时间:2018-11-11 23:42:36

标签: python python-3.x exception doctest

以下玩具脚本说明了该问题:

#!/usr/bin/env python3

def bomb():
    """
    >>> bomb()
    Traceback (most recent call last):
      File "<string>", line 18, in bomb
    ZeroDivisionError: division by zero
    <BLANKLINE>
    During handling of the above exception, another exception occurred:
    <BLANKLINE>
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<string>", line 20, in bomb
    Exception: re-raised
    """
    try:
        1/0
    except Exception as exception:
        raise Exception('re-raised')

if __name__ == '__main__' and '__file__' in globals():
    import sys
    if len(sys.argv) > 1 and sys.argv[1] == '-t':
        import doctest
        doctest.testmod()
    else:
        bomb()

如果我在python解释器中执行bomb(),则会得到由文档字符串指定的输出:

% python3
Python 3.5.1 (default, May 24 2016, 20:04:39)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> exec(open('demo.py').read())
>>> bomb()
Traceback (most recent call last):
  File "<string>", line 18, in bomb
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 20, in bomb
Exception: re-raised
>>>

doctest,但是,错误地报告了失败:

**********************************************************************
File "./demo.py", line 5, in __main__.bomb
Failed example:
    bomb()
Expected:
    Traceback (most recent call last):
      File "<string>", line 16, in bomb
    ZeroDivisionError: division by zero
    <BLANKLINE>
    During handling of the above exception, another exception occurred:
    <BLANKLINE>
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<string>", line 18, in bomb
    Exception: re-raised
Got:
    Traceback (most recent call last):
      File "./demo.py", line 18, in bomb
        1/0
    ZeroDivisionError: division by zero
    <BLANKLINE>
    During handling of the above exception, another exception occurred:
    <BLANKLINE>
    Traceback (most recent call last):
      File "/usr/lib/python3.5/doctest.py", line 1320, in __run
        compileflags, 1), test.globs)
      File "<doctest __main__.bomb[0]>", line 1, in <module>
        bomb()
      File "./demo.py", line 20, in bomb

1 个答案:

答案 0 :(得分:0)

问题是doctest在内部如何工作。基本上,它会在同一python解释器中加载,编译和评估python的代码段。

这与python加载和执行给定代码段的方式不同。

这是做神奇的doctest片段:

# Don't blink!  This is where the user's code gets run.
exec(compile(example.source, filename, "single",
     compileflags, 1), test.globs)

当执行的代码引发异常时,回溯包含doctest引擎的堆栈框架的一部分,从而使其与您的期望有所不同。

来自doctest documentation

  

traceback标头后面是可选的traceback堆栈,其堆栈   内容被doctest忽略。追溯堆栈通常是   省略,或从交互式会话中逐字复制。

现在,它的最后一部分似乎仅适用于单个例外; “多重或嵌套异常”不能那样工作,您可能无法检查其回溯。参见此thread

如果您仍然要检查此内容,则可以使用另一个{doc}引擎,例如byexample。它具有compatibility mode with doctest,因此您无需重写所有内容。

免责声明:我是byexample的作者。正如我在thread中所解释的那样,我是doctest的忠实拥护者,但它有其局限性。我希望byexample可以填补空白并对其他人有用。