4

我编写了一个assert_raised用于测试的上下文管理器,它检查是否引发了预期的异常,如果没有引发AssertionError. 我还编写了一个 doctest 来测试它,但是 doctest 一直失败,我不完全确定为什么。这是文档测试:

>>> for e in [TypeError, ValueError, KeyError]:
...     with assert_raised(TypeError, ValueError):
...         print('Raising {}...'.format(e.__name__))
...         raise e
Raising TypeError...
Raising ValueError...
Raising KeyError...
Traceback (most recent call last):
    ...
AssertionError: Got 'KeyError', expected 'TypeError, ValueError'

引发的实际异常是:

Traceback (most recent call last):
  File "<doctest dtlibs.mock.assert_raised[3]>", line 4, in <module>
    raise e
KeyError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Python32\lib\doctest.py", line 1253, in __run
    compileflags, 1), test.globs)
  File "<doctest dtlibs.mock.assert_raised[3]>", line 4, in <module>
    raise e
  File "G:\Projects\Programming\dt-tools\dtlibs\dtlibs\mock.py", line 274, in __exit__
    raise self._exception(exc_type.__name__)
AssertionError: Got 'KeyError', expected 'TypeError, ValueError'

我认为实现并不重要,但如果我在那里做错了什么(没有 doctest):

class assert_raised:

    def __init__(self, *exceptions):
        self.exceptions = exceptions

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type is None:
            raise self._exception('None')
        elif self.exceptions and exc_type not in self.exceptions:
            raise self._exception(exc_type.__name__)
        return True

    def _exception(self, got):
        if len(self.exceptions) == 0:
            expected = 'an exception'
        else:
            expected = ', '.join(e.__name__ for e in self.exceptions)
        msg = "Got '{}', expected '{}'".format(got, expected)
        return AssertionError(msg)
4

1 回答 1

4

Doctests 有处理引发异常的特殊代码。因此,它会识别输出何时是异常。为了识别这一点,预期的输出必须以单词开头Traceback。您的预期输出不是以此开头的,因此,doctest 不会将输出识别为预期异常,因此,它不会预期异常,因此当异常出现时,它将失败。

您可以通过三种方式解决此问题:

  1. 去掉Raising XXXError...部分输出。[懒惰的]

  2. 为 doctest 实施特殊的输出过滤器,使 doctest 可以忽略Raising XXXError...-part [复杂]

  3. 停止将 doctest 用于测试文档以外的其他事情。[正确的]

上面的代码显然不是如何使用这个上下文管理器的示例代码,它是测试上下文管理器工作的代码。这样的测试不应该是 doctests。Doctests 是痛苦和有限的,应该只用于测试文档。

于 2012-04-10T07:22:50.397 回答