Фабула. До какого-то времени все тестовые классы наследовались от родного пайтоновского unittest.TestCase’а, а пайтест использовался для параллелизации и автоматического построения отчётов о тестировании. Со временем, мы решили отказаться от использования unittest’а в пользу пайтеста ради хороших фичей (удобная параметризация тестов, например), но тут же столкнулись с проблемой получения некоей информации об упавшем тесте (урл, скриншот, юзер и т.д.). Раскопки гугла и толчок в верном направлении от @polusok натолкнули на следующее решение.
В нашей практике мы используем базовый тестовый класс, в котором объявлено несколько кастомных методов для общего использования. В нём создаём некий метод get_fail_debug(), который вернёт нам всю необходимую информацию.
def get_fail_debug(self):
"""Failed test report generator"""
print 'Fail debug info:\n'
alerts = 0
try:
while self.driver.switch_to_alert():
alert = self.driver.switch_to_alert()
print 'Unexpected ALERT: ' + alert.text
alerts += 1
alert.dismiss()
except:
if alerts != 0:
print ''
pass
url = self.get_fail_url() # Custom method to get url with autologin key for quick access
print 'Fail URL: ' + url
now = datetime.now().strftime('%d_%H-%M-%S-%f') # For creating unique filenames
if not os.path.exists("/opt/workspace/screenshots/"):
os.makedirs("/opt/workspace/screenshots/")
try:
self.driver.save_screenshot('/opt/workspace/screenshots/%s.png' % now)
fail_screenshot_url = 'http://some_service/screenshots/%s.png' % now
except Exception as e:
fail_screenshot_url = 'No screenshot was captured due to exception %s' % e.message
print 'Fail SCRENSHOT: ' + fail_screenshot_url
if self.logged_in_user:
user = 'id: %s, email: %s' % (self.logged_in_user.id, self.logged_in_user.email)
else:
user = 'Guest'
print 'User: ' + user
в setup_method(self, method)
того-же базового класса добавляем такую строку
pytest.config.get_fail_debug = self.get_fail_debug
На выходе имеем, что каждый отдельно взятый тест в курсе об этом методе
Ну и самое интересное, в conftest.py объявляем функцию, в которой куча всякой магии, но нужно поверить, что так делать правильно:
def pytest_runtest_makereport(__multicall__, item, call):
"""pytest failed test report generator"""
report = __multicall__.execute()
if report.when == 'call':
report.session_id = getattr(item, 'session_id', None)
if report.skipped and 'xfail' in report.keywords or report.failed and 'xfail' not in report.keywords:
try:
item.config.get_fail_debug() # Вызываем тот самый метод из базового класса
except:
print 'Error collecting debug information. Webdriver instance must have crushed'
return report
Ну и и поломанный тест выглядит примерно так:
<Пропущенный трейсбэк>
E assert None
----------------- Captured stdout -------------
Fail debug info:
Fail URL: http://example.com/some_page.html
Fail SCRENSHOT: http://some_service/screenshots/14_19-56-21-389139.png
User: Guest
Надеюсь, кому-то поможет.
PS На правах рекламы, @polusok обещает делиться секретами мастерства за вот такие вот заметки
PPS Сделайте выбор нескольких рубрик, что ли