wim*_*wim 8 python testing logging exception-handling pytest
我的应用程序记录未处理的异常.
# app.py
import logging
import sys
logger = logging.getLogger(__name__)
def excepthook(exc_type, exc_value, traceback):
exc_info = exc_type, exc_value, traceback
if not issubclass(exc_type, (KeyboardInterrupt, SystemExit)):
logger.error('Unhandled exception', exc_info=exc_info)
sys.__excepthook__(*exc_info)
sys.excepthook = excepthook
def potato():
logger.warning('about to die...')
errorerrorerror
if __name__ == '__main__':
potato()
Run Code Online (Sandbox Code Playgroud)
这些测试通过OK:
# test_app.py
import app
import pytest
import sys
from logging import WARNING, ERROR
def test_potato_raises():
with pytest.raises(NameError):
app.potato()
def test_excepthook_is_set():
assert sys.excepthook is app.excepthook
# for caplog plugin: pip install pytest-catchlog
def test_excepthook_logs(caplog):
try:
whatever
except NameError as err:
exc_info = type(err), err, err.__traceback__
app.excepthook(*exc_info)
assert caplog.record_tuples == [('app', ERROR, 'Unhandled exception')]
[record] = caplog.records
assert record.exc_info == exc_info
Run Code Online (Sandbox Code Playgroud)
但我无法测试未处理的异常日志记录工作:
def test_unhandled_exceptions_logged(caplog):
try:
app.potato()
finally:
assert caplog.record_tuples == [
('app', WARNING, 'about to die...'),
('app', ERROR, 'Unhandled exception'),
]
return # return eats exception
Run Code Online (Sandbox Code Playgroud)
这有什么不对?我们怎样才能app.excepthook在测试中实际触发?
Python 不会调用,sys.excepthook直到异常真正传播到整个堆栈并且没有更多的代码有机会捕获它。这是 Python 关闭以响应异常之前发生的最后一件事。
只要您的测试代码仍在堆栈中,sys.excepthook就不会触发。实际上可以运行的小代码sys.excepthook可能不会与您的测试框架很好地配合使用。例如,atexit处理程序仍然可以运行,但到那时测试已经结束。此外,如果您不这样做,您的测试框架可能会自行捕获异常,因此sys.excepthook无论如何都不会触发。
如果您不想给sys.excepthook自己打电话,最好的办法可能是在您excepthook安装的情况下启动整个子流程并验证子流程的行为。
from subprocess import Popen, PIPE
def test_app():
proc = Popen([sys.executable, 'app.py'], stdout=PIPE, stderr=PIPE)
stdout, stderr = proc.communicate()
assert proc.returncode == 1
assert stdout == b''
assert stderr.startswith(b'about to die...\nUnhandled exception')
Run Code Online (Sandbox Code Playgroud)