Python doctest很酷。让我从一个简单的例子开始:
def foo():
"""
>>> foo()
hello world
"""
print "hello world"
现在,假设某些部分有所变化,例如,因为它是时间值或随机数。通常,doctest允许我使用+ ELLIPSIS选项指定通配符。
例如,当“ world”是一个可变的字符串时,这很好用:
def foo():
"""
>>> foo() # doctest: +ELLIPSIS
hello ...
"""
print "hello world"
但是,在我的情况下,可变字符串在行的开头:
def foo():
"""
>>> foo() # doctest: +ELLIPSIS
... world
"""
print "hello world"
这很不好,因为开头的3个点被解释为行连续字符,而不是输出的省略号。因此,此测试失败:
Failed example:
foo() # doctest: +ELLIPSIS
world
Expected nothing
Got:
hello world
因此,我现在可以重写我的代码,以使变量部分位于其他位置,但是有什么方法可以教文档测试该行开头的三个点是省略号吗?
这是给您的快速又肮脏的技巧:
def foo():
"""
>>> foo() # doctest: +ELLIPSIS
[...] world
"""
print "hello world"
if __name__ == "__main__":
import doctest
OC = doctest.OutputChecker
class AEOutputChecker(OC):
def check_output(self, want, got, optionflags):
from re import sub
if optionflags & doctest.ELLIPSIS:
want = sub(r'\[\.\.\.\]', '...', want)
return OC.check_output(self, want, got, optionflags)
doctest.OutputChecker = AEOutputChecker
doctest.testmod()
这仍然可以理解普通的(...)省略号,但是它添加了一个新的([...]),不会引起行起始歧义。
对于doctest来说,很难猜测是否存在行继续符或行开始省略号-从理论上讲,如果您将DocTestParser子类化即可完成这项工作,但是这样做可能会很有趣, 。
在复杂的情况下,您可能应该使用自己的DocTestRunner进行滚动,该操作将使用新的OutputChecker并使用它代替普通的testmod,但是在简单的情况下应该这样做。
您可以为测试更新ELLIPSIS_MARKER
,以使...
不会与行连续点混淆:
def foo():
"""
>>> import doctest
>>> doctest.ELLIPSIS_MARKER = '-ignore-'
>>> foo()
hello world
>>> foo() # doctest: +ELLIPSIS
-ignore- world
"""
print "hello world"
if __name__ == "__main__":
import doctest
doctest.testmod()
Disclaimer:当doctests以
运行时,以上示例适用$ py.test --doctest-module foo.py
或
$ python foo.py
但是,由于我不明白的原因,通过以下方式运行doctest时,它不起作用:>
$ python -m doctest foo.py
这里是一种较为简单的方法:只需在以未知输出开头的行之前打印一个虚拟字符串即可。
我最终解决了这个问题。