Eli*_*ght 9 python doctest warnings
我想使用doctests测试某些警告的存在.例如,假设我有以下模块:
from warnings import warn
class Foo(object):
"""
Instantiating Foo always gives a warning:
>>> foo = Foo()
testdocs.py:14: UserWarning: Boo!
warn("Boo!", UserWarning)
>>>
"""
def __init__(self):
warn("Boo!", UserWarning)
Run Code Online (Sandbox Code Playgroud)
如果我跑到python -m doctest testdocs.py我班上运行doctest并确保打印警告,我得到:
testdocs.py:14: UserWarning: Boo!
warn("Boo!", UserWarning)
**********************************************************************
File "testdocs.py", line 7, in testdocs.Foo
Failed example:
foo = Foo()
Expected:
testdocs.py:14: UserWarning: Boo!
warn("Boo!", UserWarning)
Got nothing
**********************************************************************
1 items had failures:
1 of 1 in testdocs.Foo
***Test Failed*** 1 failures.
Run Code Online (Sandbox Code Playgroud)
看起来警告正在打印但未被doctest捕获或注意到.我猜这是因为警告打印sys.stderr而不是sys.stdout.但即使我sys.stderr = sys.stdout在模块结束时说这种情况也会发生.
那么有没有办法使用doctests来测试警告?我在文档或Google搜索中都没有提到这种方式.
Python 文档的测试警告部分专门讨论此主题。但是,总而言之,您有两种选择:
catch_warnings上下文管理器这是官方文档中推荐的课程。然而,catch_warnings上下文管理器仅在 Python 2.6 中出现。
import warnings
def fxn():
warnings.warn("deprecated", DeprecationWarning)
with warnings.catch_warnings(record=True) as w:
# Cause all warnings to always be triggered.
warnings.simplefilter("always")
# Trigger a warning.
fxn()
# Verify some things
assert len(w) == 1
assert issubclass(w[-1].category, DeprecationWarning)
assert "deprecated" in str(w[-1].message)
Run Code Online (Sandbox Code Playgroud)
如果警告以前没有出现过,因此已在警告注册表中注册,那么您可以设置警告来引发异常并捕获它。
import warnings
def fxn():
warnings.warn("deprecated", DeprecationWarning)
if __name__ == '__main__':
warnings.simplefilter("error", DeprecationWarning)
try:
fxn()
except DeprecationWarning:
print "Pass"
else:
print "Fail"
finally:
warnings.simplefilter("default", DeprecationWarning)
Run Code Online (Sandbox Code Playgroud)
这不是最优雅的方法,但它对我有用:
from warnings import warn
class Foo(object):
"""
Instantiating Foo always gives a warning:
>>> import sys; sys.stderr = sys.stdout
>>> foo = Foo() # doctest:+ELLIPSIS
/.../testdocs.py:14: UserWarning: Boo!
warn("Boo!", UserWarning)
"""
def __init__(self):
warn("Boo!", UserWarning)
if __name__ == '__main__':
import doctest
doctest.testmod()
Run Code Online (Sandbox Code Playgroud)
不过,这可能在 Windows 上不起作用,因为 UserWarning 输出中报告的路径必须以斜杠开头,就像我编写此测试的方式一样。您也许能够找出 ELLIPSIS 指令的一些更好的咒语,但我不能。