Как обнаружить, когда тест теста pytest не удался?
Я использую pytest с селеном для автоматизации веб-сайта. Я хочу сделать снимок экрана только в случае сбоя теста. Я уже использовал 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()
выполняется только тогда, когда нет ошибок
Ответы
Ответ 1
Согласно вам post в stackoverflow, я могу поделиться тем, что я что-то на уме, надеюсь, это поможет: wink:
То, что вы пытаетесь сделать, это обработать стандартное исключение AssertionError, которое может быть поднято assert или любым метод утверждения, реализованный в unittest.TestCase или, возможно, какой-либо пользовательский метод утверждения, который вызывает настраиваемое исключение.
Есть 3 способа сделать это:
-
Используйте try-except-finally. Пример:
try:
Assert.fail("failed test")
except AssertionError:
get_screenshot()
raise
-
Или используйте с, как менеджер контекста:
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")
здесь вы можете погрузиться глубже в том, как играть с ним
-
Последний, на мой взгляд, самый элегантный подход. Используя декораторы . С помощью этого декоратора вы можете украсить любой метод тестирования:
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")
Ответ 2
После некоторой борьбы, в конечном итоге это сработало для меня.
В 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
Обратите внимание, что "запрос" - это "funcarg", который предоставляет pytest в контексте ваших тестов. Вам не обязательно определять его самостоятельно.
Источники: примеры pytest и thread on (not) making это проще.
Ответ 3
Вот как мы это делаем, отметим, что __ multicall __ имеет очень мало документации, и я помню, что чтение __ multicall __ будет устаревать, пожалуйста, используйте это с щепоткой соли и эксперимент с заменой __ multicall __ на элемент < , вызов "в соответствии с примерами.
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
Ответ 4
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))