[英]How can I determine if a test passed or failed by examining the Item object passed to the pytest_runtest_teardown?
Pytest allows you to hook into the teardown phase for each test by implementing a function called pytest_runtest_teardown
in a plugin: Pytest允许您通过在插件中实现名为
pytest_runtest_teardown
的函数来挂钩每个测试的拆解阶段:
def pytest_runtest_teardown(item, nextitem):
pass
Is there an attribute or method on item
that I can use to determine whether the test that just finished running passed or failed? 是否有一个属性或方法
item
,我可以用它来确定刚刚完成的测试运行是否通过或失败? I couldn't find any documentation for pytest.Item
and hunting through the source code and playing around in ipdb
didn't reveal anything obvious. 我找不到
pytest.Item
任何文档和通过源代码搜索并在ipdb
玩ipdb
并没有发现任何明显的东西。
You may also consider call.excinfo in pytest_runtest_makereport: 您也可以在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.')
The call object contains a whole bunch of additional information (test start time, stop time, etc.). 调用对象包含一大堆附加信息(测试开始时间,停止时间等)。
Refer: http://doc.pytest.org/en/latest/_modules/_pytest/runner.html 请参阅: 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)
The Node
class don't have any information regarding the status of the last test, however we do have the status of the total number of failed tests (in item.session.testsfailed
), and we can use it: Node
类没有关于上一次测试状态的任何信息,但是我们确实具有失败测试总数的状态(在item.session.testsfailed
),我们可以使用它:
item.session
object (not so nice, but you gotta love python!). item.session
对象中添加一个新成员(不太好,但你必须爱python!)。 This member will save the status of the last testsfailed
- item.session.last_testsfailed_status
. testsfailed
item.session.last_testsfailed_status
的状态 - item.session.last_testsfailed_status
。 testsfailed
> last_testsfailed_status
- the last test the run just failed. testsfailed
> 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
Initially, I was also struggling to get the Test Status, so that I can use it to make a custom report. 最初,我也在努力获得测试状态,以便我可以使用它来制作自定义报告。
But, after further analysis of pytest_runtest_makereport hook function, I was able to see various attributes of 3 params (item, call, and report). 但是,在进一步分析pytest_runtest_makereport钩子函数后,我能够看到3个参数(项目,调用和报告)的各种属性。 Let me just list some of it out:
让我列出一些:
FYI: there are other attributes for all the above 3 params, I have mentioned in few. 仅供参考:以上3种方式都有其他属性,我已经提到了很少。 Below is the code snipped depicting, of how I have hooked the function and used.
下面是代码剪辑描述,我如何钩住函数和使用。
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
Hook wrappers are the way to go - allow all the default hooks to run & then look at their results. Hook包装器是可行的方法 - 允许所有默认挂钩运行,然后查看其结果。
Below example shows 2 methods for detecting whether a test has failed (add it to your conftest.py
) 下面的示例显示了检测测试是否失败的2种方法(将其添加到
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')
See TestReport
documentation for details of longrepr
and outcome
有关
longrepr
和outcome
详细信息,请参阅TestReport
文档
(It doesn't use pytest_runtest_teardown
as the OP requested but it does easily let you check for failure) (它不使用
pytest_runtest_teardown
作为请求的OP,但它很容易让你检查失败)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.