Удаленка для jenkins+selenide+selenoid+allure+docker спецов на 2-3 часа в день. 100% remote! Присоединиться к проекту

Прикрепление скриншотов через selene к allure-отчету

selene
allure
python
Теги: #<Tag:0x00007fedbbc4bde0> #<Tag:0x00007fedbbc4bc78> #<Tag:0x00007fedbbc4bac0>

(Maxim Zaitsev) #1

Коллеги, приветствую.
Использую в проекте связку pytest+selene+allure. Отчеты по тестам планирую размещать через Jenkins. Возник такой вопрос:
По умолчанию, selene сохраняет скриншот при фейле в системную папку пользователя, в отчете, соответственно, содержится только информация о пути к файлу. А хотелось бы, чтобы скриншоты были прикреплены к самому отчету.
Оборачивать каждую проверку в try-except + allure.attach - явно неэффективный путь.

Нет ли более красивых способов ?

P.S. Версию selene использую предрелизную (pip install selene --pre)


(rmerkushin) #2

Посмотрите тут Как записать скриншот если тест падает allure ?


(Maxim Zaitsev) #3

Спасибо, за наводку. Даж когда-то читал эту тему xD. В этом варианте мне придется каждый тест(или класс) отметить фикстурой. Неплохо. Но хочется лучше.
Selene так и так делает скриншот. Всего-то нужно изменить подход: вместо сохранения в папку, прикреплять к отчету. Может у разработчиков есть планы по реализации такого функционала через конфиг ? @Ayia @Sergey_Pirogov


(Sergey Pirogov) #4

Не вместо, а просто крепить к отчету. В selene есть метод get_latest_screenshot


(Maxim Zaitsev) #5

Да, метод такой есть. И я так понимаю, возможный вариант его использования следующий:
в базовый класс тестов в teardown_method я прописываю функцию, которая будет проверять, есть ли последний скриншот, и если есть, то прикреплять его к отчету.

Безусловно, это вариант будет лучше, чем прописывать фикстуры для каждого класса. Но отчет будет выглядеть коряво: файл со скриншот прикрепится в самый конец (а в не шаге с ошибкой) + будет информация о скриншоте, сохраненным на диск (а этот файл скорее всего не будет доступен пользователю). Ну и сам скриншот будет занимать места на харде в два раза больше.
Все верно?


(Sergey Pirogov) #6

Не верно. Посмотрите на форуме уже рассказывали как на экстеншин поставить вызов скриншота и прикрепить к отчету


(Вадим) #7

Добрый день, подскажите. Как вы реализовали добавления скриншота к отчету. Спасибо


(Maxim Zaitsev) #8

Пока остановился на варианте с хуком pytest_exception_interact

Скриншот прикрепляется к отчету, но и дублируется в папку, указанную в конфиге selene.


(Вадим) #9

Наверное глупый вопрос, но где мне найти этот файл conftest.py ? Использую virtualenv мне непосредственно там надо найти и прописать pytest_exception_interact в conftest.py?


(Maxim Zaitsev) #10

Файл conftest.py создается вручную и размещается в папке с тестами. Например, в такой структуре:

project_folder
  - tests
      -- conftest.py
      -- test_something.py
      -- test_something_2.py

(Вадим) #11

Структуру понял, спасибо.
Добавил файл в conftest.py.
Вот такого он формата:
#!/usr/bin/env python
# -- coding: utf-8 --
# coding: utf8

import allure

def pytest_exception_interact(node, call, report):
** driver = node.instance.driver**
** allure.attach(**
** name=‘Скриншот’,**
** contents=driver.get_screenshot_as_png(),**
** type=allure.constants.AttachmentType.PNG,**
** )**

Но при запуске такое выводит:

INTERNALERROR> Traceback (most recent call last):
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/main.py”, line 110, in wrap_session
INTERNALERROR> session.exitstatus = doit(config, session) or 0
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/main.py”, line 146, in _main
INTERNALERROR> config.hook.pytest_runtestloop(session=session)
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 745, in call
INTERNALERROR> return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 339, in _hookexec
INTERNALERROR> return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 334, in
INTERNALERROR> _MultiCall(methods, kwargs, hook.spec_opts).execute()
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 614, in execute
INTERNALERROR> res = hook_impl.function(*args)
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/main.py”, line 169, in pytest_runtestloop
INTERNALERROR> item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 745, in call
INTERNALERROR> return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 339, in _hookexec
INTERNALERROR> return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 334, in
INTERNALERROR> _MultiCall(methods, kwargs, hook.spec_opts).execute()
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 613, in execute
INTERNALERROR> return _wrapped_call(hook_impl.function(*args), self.execute)
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 254, in _wrapped_call
INTERNALERROR> return call_outcome.get_result()
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 280, in get_result
INTERNALERROR> _reraise(*ex) # noqa
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 265, in init
INTERNALERROR> self.result = func()
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 613, in execute
INTERNALERROR> return _wrapped_call(hook_impl.function(*args), self.execute)
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 254, in _wrapped_call
INTERNALERROR> return call_outcome.get_result()
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 280, in get_result
INTERNALERROR> _reraise(*ex) # noqa
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 265, in init
INTERNALERROR> self.result = func()
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 613, in execute
INTERNALERROR> return _wrapped_call(hook_impl.function(*args), self.execute)
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 254, in _wrapped_call
INTERNALERROR> return call_outcome.get_result()
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 280, in get_result
INTERNALERROR> _reraise(*ex) # noqa
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 265, in init
INTERNALERROR> self.result = func()
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 614, in execute
INTERNALERROR> res = hook_impl.function(*args)
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/runner.py”, line 68, in pytest_runtest_protocol
INTERNALERROR> runtestprotocol(item, nextitem=nextitem)
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/runner.py”, line 82, in runtestprotocol
INTERNALERROR> reports.append(call_and_report(item, “call”, log))
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/runner.py”, line 168, in call_and_report
INTERNALERROR> hook.pytest_exception_interact(node=item, call=call, report=report)
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 745, in call
INTERNALERROR> return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 339, in _hookexec
INTERNALERROR> return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 334, in
INTERNALERROR> _MultiCall(methods, kwargs, hook.spec_opts).execute()
INTERNALERROR> File “/Users/user/Desktop/autotesting2/config/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py”, line 614, in execute
INTERNALERROR> res = hook_impl.function(*args)
INTERNALERROR> File “/Users/user/Desktop/autotesting2/conftest.py”, line 9, in pytest_exception_interact
INTERNALERROR> driver = node.instance.driver
INTERNALERROR> AttributeError: TestSomeCase instance has no attribute ‘driver’

Или файл надо положить в virtualenv ?


(Maxim Zaitsev) #12

Конечно, pytest traceback’i , бывают непонятными, но в данном случае, все очевидно.
В объекте класса TestSomeCase нет свойства ‘driver’

Каким образом у тебя драйвер попадает в тестовый класс ?


(Вадим) #13

Использую Selene, при импорте его, как я понимаю и подтягивается драйвер.
Или його явно надо объявить ?


(Maxim Zaitsev) #14

значит попробуй его импортнуть в этот хук напрямую:


def pytest_exception_interact(node, call, report):
    from selene.browser import driver    
    # ...
    allure.attach(
        name='Скриншот',
        contents=driver().get_screenshot_as_png(),
        type=allure.constants.AttachmentType.PNG,
    )
    # ...

(Вадим) #15

Данный хук работает, вот как выглядит финальный файл для селена

def pytest_exception_interact(node, call, report):
driver = node.instance.driver
# …
allure.attach(
name=‘Скриншот’,
body=browser.driver().get_screenshot_as_png(),
attachment_type=allure.attachment_type.PNG,
)
# …

  • надо явно указать драйвер перед кейсами (для селена это так driver = browser.driver())

(Igor Balagurov) #16

тесты запускал в PyCharm? из консоли ошибка та же? INTERNALERROR может быть от самого PyCharm


(Вадим) #17

Перенес тесты на сервер. Теперь при “фэйле” тестов ошибка в файле conftest.py в котором лежит мой хук

INTERNALERROR> File “/home/autotesting2/conftest.py”, line 20, in pytest_exception_interact
INTERNALERROR> attachment_type=allure.attachment_type.PNG,
INTERNALERROR> AttributeError: ‘module’ object has no attribute ‘attachment_type’

Как я понимаю что какой-то модуль не установлен, может подскажите какой ?


(Maxim Zaitsev) #18

Я полагаю, что дело не в модуле. Как-то криво код написан. Насколько я вижу по коду allure там нет свойства attachment_type.

Попробуй, как в моем примере: