简体   繁体   English

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

[英]How to test nested/re-raised exceptions with doctest?

The following toy script illustrates the problem:以下玩具脚本说明了这个问题:

#!/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()

If I execute bomb() in the python interpreter, I get the output specified by the docstring:如果我在 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 , however, incorrectly reports a failure:但是, 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

The problem is how the doctest internally works.问题是 doctest 内部是如何工作的。 Basically it loads, compiles and evals the snippets of python inside the same python interpreter.基本上它在同一个 python 解释器中加载、编译和评估 python 的片段。

This is different in how python loads and executes a given piece of code.这与 python 加载和执行给定代码的方式不同。

This is the snippet of doctest that does the magic:这是具有魔力的 doctest 片段:

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

When the executed code raise and exception, the traceback contains part of the stack frame of the doctest engine making it different from what you expect.当执行的代码引发异常时,回溯包含 doctest 引擎的堆栈帧的一部分,使其与您期望的不同。

From the doctest documentation :doctest 文档

The traceback header is followed by an optional traceback stack, whose contents are ignored by doctest.回溯头后面是一个可选的回溯堆栈,doctest 会忽略其内容。 The traceback stack is typically omitted, or copied verbatim from an interactive session.回溯堆栈通常被省略,或从交互式会话中逐字复制。

Now, the last part of that seems that applies only for single exceptions ;现在,最后一部分似乎适用于单个异常 "multi or nested exceptions" don't work like that way and you may not be able to check their tracebacks. “多重或嵌套异常”不会像那样工作,您可能无法检查它们的回溯。 See this thread .看到这个线程

If you still want to check this, you could use another "doctest engine" like byexample .如果您仍然想检查这一点,您可以使用另一个“doctest 引擎”,例如byexample It has a compatibility mode with doctest so you should not need to rewrite everything.它具有与 doctest兼容模式,因此您无需重写所有内容。

Disclaimer: I'm the author of byexample .免责声明:我是byexample的作者。 An as I explained in this thread I'm a really big fan of doctests but it has its limitations.正如我在此线程中所解释的那样,我非常喜欢 doctests,但它有其局限性。 I hope that byexample could fill the gap and be useful for other people.我希望byexample可以填补空白并对其他人有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM