如何检测pytest测试用例何时失败?
How to detect when pytest test case failed?
我正在使用 pytest 和 selenium 来自动化网站。我只想在测试用例失败时拍摄一些屏幕截图。我以前使用过 TestNG,对于 TestNG,使用 ITestListner 非常简单。
我们在 pytest 中有类似的东西吗?
我尝试使用 teardown_method() 来实现这一点
但是当测试用例失败时,这个方法不会被执行。
import sys
from unittestzero import Assert
class TestPY:
def setup_method(self, method):
print("in setup method")
print("executing " + method.__name__)
def teardown_method(self, method):
print(".....teardown")
if sys.exc_info()[0]:
test_method_name = method
print test_method_name
def test_failtest(self):
Assert.fail("failed test")
teardown_method()
只有在没有失败时才执行
这就是我们的做法,注意 __multicall__ 的文档非常少,我记得读过 __multicall__ 将被弃用,请用少许盐使用它并尝试将 __multicall__ 替换为 'item, call'根据示例。
def pytest_runtest_makereport(__multicall__):
report = __multicall__.execute()
if report.when == 'call':
xfail = hasattr(report, 'wasxfail')
if (report.skipped and xfail) or (report.failed and not xfail):
try:
screenshot = APP_DRIVER.take_screen_shot(format="base64")
except Exception as e:
LOG.debug("Error saving screenshot !!")
LOG.debug(e)
return report
根据您在 Whosebug 上 的说法,我可以分享我的想法,我希望它会 help:wink:
您要做的是处理标准 AssertionError 异常,该异常可以由 assert keyword or by any assertion method implemented in unittest.TestCase 或任何引发自定义异常的自定义断言方法引发。
有 3 种方法可以做到这一点:
使用try-except-finally构造。一些基本示例:
try:
Assert.fail("failed test")
except AssertionError:
get_screenshot()
raise
或使用with语句,作为上下文管理器:
class TestHandler:
def __enter__(self):
# maybe some set up is expected before assertion method call
pass
def __exit__(self, exc_type, exc_val, exc_tb):
# catch whether exception was raised
if isinstance(exc_val, AssertionError):
get_screenshot()
with TestHandler():
Assert.fail("failed test")
here you can dive deeper on how to play with it
在我看来,最后一种是最优雅的方法。使用 decorators。使用这个装饰器你可以装饰任何测试方法:
def decorator_screenshot(func):
def wrapper(*args, **kwargs):
try:
func(*args, **kwargs)
except AssertionError:
get_screenshot()
raise
return wrapper
@decorator_screenshot
def test_something():
Assert.fail("failed test")
经过一番努力,最终这对我有用。
在conftest.py中:
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_makereport(item, call):
outcome = yield
rep = outcome.get_result()
setattr(item, "rep_" + rep.when, rep)
return rep
并且,在您的代码中,在夹具中(例如,在用于测试的拆卸夹具中)像这样使用它:
def tear_down(request):
method_name = request.node.name
if request.node.rep_call.failed:
print('test {} failed :('.format(method_name))
# do more stuff like take a selenium screenshot
请注意,"request" 是 pytest 在您的测试上下文中提供的固定装置 "funcarg"。您不必自己定义它。
def pytest_runtest_makereport(item, call):
if call.when == 'call':
if call.excinfo is not None:
# if excinfor is not None, indicate that this test item is failed test case
error("Test Case: {}.{} Failed.".format(item.location[0], item.location[2]))
error("Error: \n{}".format(call.excinfo))
我正在使用 pytest 和 selenium 来自动化网站。我只想在测试用例失败时拍摄一些屏幕截图。我以前使用过 TestNG,对于 TestNG,使用 ITestListner 非常简单。 我们在 pytest 中有类似的东西吗?
我尝试使用 teardown_method() 来实现这一点 但是当测试用例失败时,这个方法不会被执行。
import sys
from unittestzero import Assert
class TestPY:
def setup_method(self, method):
print("in setup method")
print("executing " + method.__name__)
def teardown_method(self, method):
print(".....teardown")
if sys.exc_info()[0]:
test_method_name = method
print test_method_name
def test_failtest(self):
Assert.fail("failed test")
teardown_method()
只有在没有失败时才执行
这就是我们的做法,注意 __multicall__ 的文档非常少,我记得读过 __multicall__ 将被弃用,请用少许盐使用它并尝试将 __multicall__ 替换为 'item, call'根据示例。
def pytest_runtest_makereport(__multicall__):
report = __multicall__.execute()
if report.when == 'call':
xfail = hasattr(report, 'wasxfail')
if (report.skipped and xfail) or (report.failed and not xfail):
try:
screenshot = APP_DRIVER.take_screen_shot(format="base64")
except Exception as e:
LOG.debug("Error saving screenshot !!")
LOG.debug(e)
return report
根据您在 Whosebug 上
使用try-except-finally构造。一些基本示例:
try: Assert.fail("failed test") except AssertionError: get_screenshot() raise
或使用with语句,作为上下文管理器:
class TestHandler: def __enter__(self): # maybe some set up is expected before assertion method call pass def __exit__(self, exc_type, exc_val, exc_tb): # catch whether exception was raised if isinstance(exc_val, AssertionError): get_screenshot() with TestHandler(): Assert.fail("failed test")
here you can dive deeper on how to play with it
在我看来,最后一种是最优雅的方法。使用 decorators。使用这个装饰器你可以装饰任何测试方法:
def decorator_screenshot(func): def wrapper(*args, **kwargs): try: func(*args, **kwargs) except AssertionError: get_screenshot() raise return wrapper @decorator_screenshot def test_something(): Assert.fail("failed test")
经过一番努力,最终这对我有用。
在conftest.py中:
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_makereport(item, call):
outcome = yield
rep = outcome.get_result()
setattr(item, "rep_" + rep.when, rep)
return rep
并且,在您的代码中,在夹具中(例如,在用于测试的拆卸夹具中)像这样使用它:
def tear_down(request):
method_name = request.node.name
if request.node.rep_call.failed:
print('test {} failed :('.format(method_name))
# do more stuff like take a selenium screenshot
请注意,"request" 是 pytest 在您的测试上下文中提供的固定装置 "funcarg"。您不必自己定义它。
def pytest_runtest_makereport(item, call):
if call.when == 'call':
if call.excinfo is not None:
# if excinfor is not None, indicate that this test item is failed test case
error("Test Case: {}.{} Failed.".format(item.location[0], item.location[2]))
error("Error: \n{}".format(call.excinfo))