Pytest允许您通过在插件中实现名为pytest_runtest_teardown
的函数来挂钩每个测试的拆解阶段:
def pytest_runtest_teardown(item, nextitem):
pass
我可以使用item
上的属性或方法来确定刚刚运行的测试是通过还是失败?我找不到pytest.Item
的任何文档,并且搜索源代码并在ipdb
中玩游戏并没有发现任何明显的内容。
答案 0 :(得分:4)
您也可以考虑pytest_runtest_makereport中的call.excinfo:
def pytest_runtest_makereport(item, call):
if call.when == 'setup':
print('Called after setup for test case is executed.')
if call.when == 'call':
print('Called after test case is executed.')
print('-->{}<--'.format(call.excinfo))
if call.when == 'teardown':
print('Called after teardown for test case is executed.')
调用对象包含大量附加信息(测试开始时间,停止时间等)。
参见: http://doc.pytest.org/en/latest/_modules/_pytest/runner.html
def pytest_runtest_makereport(item, call):
when = call.when
duration = call.stop-call.start
keywords = dict([(x,1) for x in item.keywords])
excinfo = call.excinfo
sections = []
if not call.excinfo:
outcome = "passed"
longrepr = None
else:
if not isinstance(excinfo, ExceptionInfo):
outcome = "failed"
longrepr = excinfo
elif excinfo.errisinstance(pytest.skip.Exception):
outcome = "skipped"
r = excinfo._getreprcrash()
longrepr = (str(r.path), r.lineno, r.message)
else:
outcome = "failed"
if call.when == "call":
longrepr = item.repr_failure(excinfo)
else: # exception in setup or teardown
longrepr = item._repr_failure_py(excinfo,
style=item.config.option.tbstyle)
for rwhen, key, content in item._report_sections:
sections.append(("Captured %s %s" %(key, rwhen), content))
return TestReport(item.nodeid, item.location,
keywords, outcome, longrepr, when,
sections, duration)
答案 1 :(得分:1)
Node
class没有关于上一次测试状态的任何信息,但我们确实有失败测试总数的状态(item.session.testsfailed
),我们可以使用它:
item.session
对象中添加一个新成员(不太好,但你必须爱上python!)。该成员将保存上一个testsfailed
- item.session.last_testsfailed_status
。testsfailed
&gt; last_testsfailed_status
- 运行失败的最后一次测试。import pytest
import logging
logging.basicConfig(
level='INFO',
handlers=(
logging.StreamHandler(),
logging.FileHandler('log.txt')
)
)
@pytest.mark.hookwrapper
def pytest_runtest_teardown(item, nextitem):
outcome = yield
if not hasattr(item.session, 'last_testsfailed_status'):
item.session.last_testsfailed_status = 0
if item.session.testsfailed and item.session.testsfailed > item.session.last_testsfailed_status:
logging.info('Last test failed')
item.session.last_testsfailed_status = item.session.testsfailed
答案 2 :(得分:0)
最初,我也很努力地获取测试状态,以便可以使用它来创建自定义报告。
但是,在进一步分析了pytest_runtest_makereport挂钩函数之后,我能够看到3个参数的各种属性(项目,调用和报告)。
让我只列出其中一些:
仅供参考:我在上文中已经提到了上述3个参数的其他属性。 下面是一些代码片段,它们描述了我如何钩住函数和如何使用它。
def pytest_runtest_makereport(item, call, __multicall__):
report = __multicall__.execute()
if (call.when == "call") and hasattr(item, '_failed_expect'):
report.outcome = "failed"
summary = 'Failed Expectations:%s' % len(item._failed_expect)
item._failed_expect.append(summary)
report.longrepr = str(report.longrepr) + '\n' + ('\n'.join(item._failed_expect))
if call.when == "call":
ExTest.name = item.nodeid
func_args = item.funcargs
ExTest.parameters_used = dict((k, v) for k, v in func_args.items() if v and not hasattr(v, '__dict__'))
# [(k, v) for k, v in func_args.items() if v and not hasattr(v, '__dict__')]
t = datetime.fromtimestamp(call.start)
ExTest.start_timestamp = t.strftime('%Y-%m-%d::%I:%M:%S %p')
ExTest.test_status = report.outcome
# TODO Get traceback info (call.excinfo.traceback)
return report
答案 3 :(得分:0)
使用挂钩包装器-允许所有默认的挂钩运行,然后查看其结果。
下面的示例显示了两种检测测试是否失败的方法(将其添加到您的conftest.py
)
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
# Because this is a hookwrapper, calling `yield` lets the actual hooks run & returns a `_Result`
result = yield
# Get the actual `TestReport` which the hook(s) returned, having done the hard work for you
report = result.get_result()
# Method 1: `report.longrepr` is either None or a failure representation
if report.longrepr:
logging.error('FAILED: %s', report.longrepr)
else:
logging.info('Did not fail...')
# Method 2: `report.outcome` is always one of ['passed', 'failed', 'skipped']
if report.outcome == 'failed':
logging.error('FAILED: %s', report.longrepr)
elif report.outcome == 'skipped':
logging.info('Skipped')
else: # report.outcome == 'passed'
logging.info('Passed')
有关longrepr
和outcome
的详细信息,请参见TestReport
文档
(它不使用pytest_runtest_teardown
作为所请求的OP,但它很容易让您检查故障)