Сделать скриншот и получить ошибку от assert

screenshot
reporting
python
Теги: #<Tag:0x00007f7b60eb4460> #<Tag:0x00007f7b60eb42d0> #<Tag:0x00007f7b60eb4168>

(Alexey) #1

Добрый день!

Пишу тесты на Python. Необходимо сделать скриншот в момент падения теста. Но я не хочу это делать через try except , т.к. хочется видеть на каком assert’е завалился тест. Подозреваю, что делать скриншот надо в tearDown перед закрытием браузера. Если кто-то знает, как это сделать правильно, то я был бы рад получить совет.

Заранее спасибо за ответы.


(rmerkushin) #2

Когда то давно делал такую штуку:


@pytest.mark.tryfirst
def pytest_runtest_makereport(item, call, __multicall__):
    rep = __multicall__.execute()
    setattr(item, "rep_" + rep.when, rep)
    return rep

@pytest.fixture(scope="function")
def screenshot_on_failure(request):
    def fin():
        driver = SeleniumWrapper().driver
        attach = driver.get_screenshot_as_png()
        if request.node.rep_setup.failed:
            allure.attach(request.function.__name__, attach, allure.attach_type.PNG)
        elif request.node.rep_setup.passed:
            if request.node.rep_call.failed:
                allure.attach(request.function.__name__, attach, allure.attach_type.PNG)
    request.addfinalizer(fin)

Это все пихается в conftest.py, потом нужный тест маркируется на использование фикстуры screenshot_on_failure. Дальше можете развить эту идею чтобы не пришлось помечать отдельные тесты :slight_smile:


(Nik Sidorenko) #3

Всё правильно. Скриншот надо делать а TearDown методе. Но браузер Вы скорее закрываете в TearDown сьюта, а скриншот можно делать в TearDown теста.
В тестовом фреймворке, который Вы используете (какой именно я не увидел) скорее всего есть несколько видов TearDown: для сьюта - запускается в конце всех тестов, для класса - запускается после всех тестовых методов класса, для теста - запускается поле каждого теста. Последний как раз нужное место.
Плюс скорее всего TearDown во фреймворке поддерживает наследование. Таким образом вырисовывается структура, что все тесты наследуются от базового тест класса, в котором объявлен TearDown с деланием скриншота. При такой структуре скриншот будет делаться в конце каждого теста.
Тестовый фреймворк также скорее всего позволяет проверить в TearDown успешность теста и сделать скриншот только для неуспешных.
Я пользуюсь подобной структурой уже долгое время, если нужны детали или схема классов, спрашивайте


(Oleg Kuzovkov) #4

Ставим @pytest.fixture(scope=“function”, autouse=True), и не нада маркировать тесты :slight_smile:


(rmerkushin) #5

Тут не все так просто. Если тест будет не юай то смысл там что то скринить? (Иногда необходимо после какой то проверки на юай ещё и в бд например что то глянуть в одном тесте)


(Oleg Kuzovkov) #6

Согласен :wink:


(Alexey) #7

Советы для py.test хороши. Но я использую unittest (мой косяк, что сразу это не указал).
На форуме нашел вот такое решение

import sys
driver = webdriver.Firefox()
  
и в методе tearDown():
if sys.exc_info()[0]:
      driver.get_screenshot_as_file('screenshot-%s.png')

Но, в инструкцию if почему-то не заходит. И, как следствие, не делается скриншот :frowning:


(Nik Sidorenko) #8

Может инструкция if sys.exc_info()[0] не совсем однозначна https://docs.python.org/3/library/sys.html#sys.exc_info
If no exception is being handled anywhere on the stack, a tuple containing three None values is returned. Otherwise, the values returned are (type, value, traceback).


(Alexey) #9

Попробовал вывести содержание sys.exc_info() до захода в if - получается (None, None, None). Либо я что-то делаю не так, либо одно из двух.


(rmerkushin) #10

Перейдите на py.test. unittest - это моветон и не комильфо :smile: А если серьезно, то py.test легко схавает ваши тесты без переделки т.к. есть совместимость, но в py.test вы получите куда больше возможностей. К тому же есть такая “няшка” как allure для py.test :slight_smile:


(Bolatbek) #11

За няшку allure - плюс )

Хотя она тестировщику и не нужна.


(rmerkushin) #12

Да, она нужна менеджерам :grinning:


(Bolatbek) #13

Умным менеджерам она тоже не нужна.


(Alexey) #14

Хоть и с опозданием, но решение было найдено.

import traceback
import sys
try:
    x=8/0
except Exception:
    print(''.join(traceback.format_exception(*sys.exc_info())))

(ex3me0) #15

Это не решение, это дабл-пенетрейшн костыль.
Скринить надо на ассерте или при экзепшене самого драйвера?
Если второе - то надо смотреть в сторону AbstractEventListener и его метода on_exception.
Для первого варианта - прям сходу не скажу, но я уверен, что оно куда проще.


(ex3me0) #16

Что касается аллюр-репортов: при падении теста тот же дженкинс шлет на мыло такую простыню с трейсбеком, что меня начинает тошнить. Гораздо проще перейти по линку и посмотреть откуда растут ноги, с понятным коротким трейсом (без всей иерархии), или увидеть конкретный ассерт, который все завалил.

Абезяне-тестировщику - репорт может ничего и не скажет. А вот автору тестов - аж бегом.