pytest: как получить список всех неудачных тестов в конце сеанса? (и при использовании xdist)

Я хотел бы получить список всех неудачных тестов для использования в конце сеанса.

Pytest позволяет вам определить ловушку pytest_sessionfinish(session, exitstatus), которая вызывается в конце сеанса, где я хочу получить этот список.

session - это _pytest.main.Session экземпляр с атрибутом items (тип list), но я не смог определить, не удалось ли пройти каждый item в этом списке.

  1. Как можно получить список всех неудачных тестов в конце сеанса?
  2. Как это можно сделать при использовании плагина pytest-xdist, когда я хотел бы получить этот список в главном процессе. Используя этот плагин, session даже не имеет атрибута items в мастере:

    def pytest_sessionfinish(session, exitstatus):
        if os.environ.get("PYTEST_XDIST_WORKER", "master") == "master":
             print(hasattr(session, "items"))  # False
    

person Itay    schedule 02.01.2018    source источник


Ответы (7)


Если вам нужны результаты тестов, вы можете использовать хук runtest_makereport:

@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    outcome = yield
    rep = outcome.get_result()
    if rep.when == 'call' and rep.failed:
        mode = 'a' if os.path.exists('failures') else 'w'
        try:  # Just to not crash py.test reporting
          pass  # the test 'item' failed
        except Exception as e:
            pass
person ANDgineer    schedule 03.01.2018
comment
Спасибо! Кажется, это хорошо работает, когда xdist не используется, и я могу сохранить неудачные тесты в глобальной переменной, которая будет использоваться pytest_sessionfinish в конце. При использовании xdist pytest_runtest_makereport вызывается только для рабочих, а не для мастера, поэтому они могут общаться через файл, но лучшее решение - использовать pytest_report_teststatus и pytest_runtest_logreport, которые вызываются в мастере и может использоваться для сбора неудавшихся тестов. - person Itay; 04.01.2018

Запустите pytest с -rf, чтобы он напечатал в конце список неудачных тестов.

От py.test --help:

  -r chars              show extra test summary info as specified by chars
                        (f)ailed, (E)error, (s)skipped, (x)failed, (X)passed,
                        (p)passed, (P)passed with output, (a)all except pP.
                        Warnings are displayed at all times except when
                        --disable-warnings is set

Вот что вы получите:

$ py.test -rf
================= test session starts =================
platform darwin -- Python 3.7.2, pytest-4.3.1, py-1.6.0, pluggy-0.7.1
[...]
=============== short test summary info ===============
FAILED test_foo.py::test_foo_is_flar
FAILED test_spam.py::test_spam_is_mostly_pork
FAILED test_eggs.py::test_eggs_are_also_spam
=== 3 failed, 222 passed, 8 warnings in 12.52 seconds ==
person Aaron V    schedule 26.03.2019
comment
Я использую pytest ... -rA, и он выдает вывод отказов перед переданным выводом, есть ли способ заставить его выдавать вывод отказов в конце? Так что меньше прокрутки вверх - person cryanbhu; 25.11.2020

Вы можете использовать опцию командной строки --result-log:

test_dummy.py:

def test_dummy_success():
    return


def test_dummy_fail():
    raise Exception('Dummy fail')

Командная строка:

$ py.test --result-log=test_result.txt

Содержимое test_result.txt

. test_dummy.py::test_dummy_success
F test_dummy.py::test_dummy_fail
 def test_dummy_fail():
 >       raise Exception('Dummy fail')
 E       Exception: Dummy fail

 test_dummy.py:6: Exception

Просто введите "F" в первом столбце и после этого будет [файл] :: [тест]

person ANDgineer    schedule 03.01.2018
comment
Я хотел бы использовать эту информацию в pytest_sessionfinish, и этот метод означает, что список неудачных тестов доступен только после выхода из процесса pytest. - person Itay; 04.01.2018

--result-log устарел. Вместо этого вы можете использовать -v для вывода имен тестовых примеров по мере их выполнения. Если вы отправите это в файл, вы можете запросить его. Итак, если вы запускаете свои тесты из скрипта, вы можете сделать что-то вроде:

pytest -v | tee log.txt
grep -E '::.*(FAILURE|ERROR)' log.txt
person z0r    schedule 22.03.2019

Мне нужен был краткий отчет о неудачных тестах и ​​параметризованных вариациях, поэтому я выбрал pytest_terminal_summary в conftest.py:

def pytest_terminal_summary(terminalreporter, exitstatus, config):
    terminalreporter.section('Failed tests')
    failures = [report.nodeid.split('::')[-1]
                for report in terminalreporter.stats.get('failed', [])]
    terminalreporter.write('\n'.join(failures) + '\n')

Если вы изучите terminalreporter._session.items, вы можете добавить в отчет больше информации, это как раз то, что я хотел.

person Joao Coelho    schedule 25.06.2019

Вы можете получить подробную информацию только о неудачных тестах и ​​сохранить журналы в файл с помощью команды ниже. Журналы также содержат трассировку каждого теста.

py.test -rf tests/ | tee logs.txt
person abdullahselek    schedule 29.01.2021

Я получил доступ к этому вопросу, пытаясь выяснить внутреннюю структуру данных для экземпляра session.

Итерируя session.items, вы можете проверить rep_call.outcome на строковое представление результата теста.

def pytest_sessionfinish(session, exitstatus):
    for item in session.items:
        print('{} {}'.format(item.name, item.rep_call.outcome))

С тривиальными тестовыми примерами вы получите это

test_positive passed
test_negative failed
person Aleks Amirkhanov    schedule 08.09.2020
comment
Мог бы дать всю функцию ... Я попробовал ваше решение ... у меня не сработало ... возможно, упомяните версию pytest, которую вы использовали ... а также распечатку результата .... и тестовый пример, который был запущен ...... - person Arindam Roychowdhury; 08.09.2020
comment
Что именно не работает? Вы пропустили тесты в своей настройке? - person Aleks Amirkhanov; 08.09.2020
comment
Говорит ... у элемента нет rep_call - person Arindam Roychowdhury; 08.09.2020
comment
Полагаю, это означает, что неудачный тест не начался. Что если вы замените item.rep_call.outcome на item.rep_call.outcome if hasattr(session_item, 'rep_call') else item.rep_setup.outcome - person Aleks Amirkhanov; 08.09.2020