[英]How to print stuff in a py.test finalizer
我正在测试一个写入日志文件的函数(它具体写入一个日志文件并不重要,它可以做任何事情,这正是引起这个问题的原因)
像这样:
def do_stuff():
with open('/tmp/mylogs.txt', 'a') as f:
f.write(str(time.time()))
f.write(' stuff done! \n')
return 42
我可以像这样测试它:
def test_doing_stuff(watch_logs):
assert do_stuff() == 42
assert do_stuff() == 43
为了调试目的,当测试失败时,我希望能够打印出新的日志内容-我可以制作一个固定装置,如下所示:
@pytest.fixture()
def watch_logs(request):
with open('/tmp/mylogs.txt') as f:
log_before = f.read()
def get_new_logs():
with open('/tmp/mylogs.txt') as f:
log_after = f.read()
return log_after.replace(log_before, '')
return get_new_logs
太好了-现在,我可以在测试中的任何时候检查日志内容:
def test_doing_stuff(watch_logs):
assert do_stuff() == 42
print(watch_logs())
assert do_stuff() == 43
print(watch_logs())
嗯-啊,那第二张打印不起作用,是在测试失败之后。
如果我的测试装置总是总是在测试结束时将日志打印出来,该怎么办? 然后pytest的stdout捕获将在失败时向我显示,但在失败时则不会向我显示!
@pytest.fixture()
def watch_logs(request):
with open('/tmp/mylogs.txt') as f:
log_before = f.read()
def get_new_logs():
with open('/tmp/mylogs.txt') as f:
log_after = f.read()
return log_after.replace(log_before, '')
def print_new_logs():
print('~' * 20 + ' logs ' + '~' * 20)
print(get_new_logs())
print('~' * 50)
request.addfinalizer(print_new_logs)
return get_new_logs
哦,但这不起作用,因为pytests的日志捕获未在测试定稿器期间发生。
所以问题是:我该如何制作一个可以完成打印工作的测试终结器?
这是一个极简的要点,没有(无关)写到日志文件的内容: https : //gist.github.com/hjwp/5154ec40a476a5c01ba6
没有记录或明确的方法来实现它,但是这里有一个技巧:
# conftest.py
def pytest_runtest_call(item):
if hasattr(item, "_request"):
if hasattr(item._request, "_addoutput_on_failure"):
item._request._addoutput_on_failure()
# test_x.py
import pytest
@pytest.fixture
def print_on_fail(request):
def add():
print ("test failed")
request._parent_request._addoutput_on_failure = add
def test_doing_stuff(print_on_fail):
assert False
我们可以考虑适当的request.addcall_on_failure(callback)
API。
使yield_fixture
案例起作用需要一些内部的可能不重要的重构。
感谢Holger自己的帮助(感谢@ hpk42!),我有了一些行之有效的方法。 只有一点魔术/ hacky。
解决方案是使用一个名为pytest_pyfunc_call
的py.test钩子以及一个名为hookwrapper
的装饰器。 它们为我提供了一种方法,可以在测试运行之前和之后挂接一些代码,而且还不受标准输出劫持的影响。
我们在conftest.py中定义一个新函数:
# conftest.py
@pytest.mark.hookwrapper
def pytest_pyfunc_call(pyfuncitem):
yield
print('this happens after the test runs')
if 'watch_logs' in pyfuncitem.funcargs:
print(pyfuncitem.funcargs['watch_logs']())
现在,如果pytest发现了使用watch_logs
固定装置的任何测试,它将在测试运行后打印其输出。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.