首页 > 解决方案 > 使用 doctest 测试异常链接和回溯输出

问题描述

如何使用 doctest 测试“多回溯”?似乎使用几个ELLIPSIS并且<BLANKLINE>不会成功:

def myfunc():
    """

    >>> myfunc()
    Traceback (most recent call last):
     ...
    ValueError: this is
    <BLANKLINE>
    The above exception was the direct cause of the following exception:
    <BLANKLINE>
    Traceback (most recent call last):
     ...
    TypeError: it

    """
    try:
        raise ValueError('this is')
    except ValueError as err:
        raise TypeError('it') from err


import doctest
doctest.testmod(optionflags=doctest.REPORT_NDIFF|doctest.ELLIPSIS)

结果:

"test.py" 23L, 490C written
**********************************************************************
File "test.py", line 4, in __main__.myfunc
Failed example:
    myfunc()
Differences (ndiff with -expected +actual):
      Traceback (most recent call last):
    -  ...
    +   File "test.py", line 17, in myfunc
    +     raise ValueError('this is')
      ValueError: this is
      <BLANKLINE>
      The above exception was the direct cause of the following exception:
      <BLANKLINE>
      Traceback (most recent call last):
    -  ...
    +   File "/usr/lib/python3.7/doctest.py", line 1329, in __run
    +     compileflags, 1), test.globs)
    +   File "<doctest __main__.myfunc[0]>", line 1, in <module>
    +     myfunc()
    +   File "test.py", line 19, in myfunc
    +     raise TypeError('it') from err
      TypeError: it
**********************************************************************
1 items had failures:
   1 of   1 in __main__.myfunc
***Test Failed*** 1 failures.

但如果我把所有东西都压扁,它会过去的:

>>> myfunc()
Traceback (most recent call last):
 ...
TypeError: it

标签: pythondoctest

解决方案


恐怕不可能以这种方式检查“多追溯”。

问题是 doctest 忽略了除异常类及其消息之外的所有内容。

在您的示例中,它将是:

TypeError: it

如果您对它的工作原理感兴趣,请检查 doctest.py 并搜索

exc_msg = traceback.format_exception_only(*exception[:2])[-1]

“exc_msg”将仅包含引发异常的详细信息:

TypeError: it

备择方案

如果可能,您可以将测试更改为不引发任何异常,而是打印所需的消息。

另一种可能性是使用另一个“doctest 引擎”,例如byexample。它的工作方式与 doctest 相同,但更灵活(此处快速概述)。

如果你有很多测试,你可能想尝试它与 doctest 的兼容模式,以避免重写所有内容。

对于您的示例,这应该是:

"""                                                                                                                            
>>> from your_module import myfunc                                                                                             
"""                                                                                                                            

def myfunc():                                                                                                                  
    """                                                                                                                        

    >>> myfunc()                                                                                                               
    Traceback (most recent call last):                                                                                         
     ...                                                                                                                       
    ValueError: this is                                                                                                        
    <BLANKLINE>                                                                                                                
    The above exception was the direct cause of the following exception:                                                       
    <BLANKLINE>                                                                                                                
    Traceback (most recent call last):                                                                                         
     ...                                                                                                                       
    TypeError: it                                                                                                              

    """                                                                                                                        
    try:                                                                                                                       
        raise ValueError('this is')                                                                                            
    except ValueError as err:                                                                                                  
        raise TypeError('it') from err

要从 shell 运行它:

byexample -l python -o '+py-doctest -py-pretty-print +ELLIPSIS' your_module.py

免责声明:我是byexample的作者。我是doctest 的忠实粉丝,但我知道它有其局限性,检查异常就是其中之一(特别是如果您在双 Python 2.x / 3.x 项目中工作)。

出于这个原因,我创建了byexample:它对我非常有用,我真的希望它对其他人有用。

在这里或在github中问我任何问题


推荐阅读