Как захватить вывод stdout/stderr
Pytest перехватывает stdout и stderr в соответствии с настройками аргумента командной строки --capture= или с помощью фикстур. Флаг --capture= настраивает отчётность, а фикстуры обеспечивают более детальный контроль и позволяют проверять вывод во время тестирования. Отчёты можно настроить с помощью флага -r.
Поведение по умолчанию при захвате stdout/stderr/stdin
Во время выполнения теста захватывается любой вывод, отправленный в stdout и stderr. Если тест или метод настройки завершается с ошибкой, соответствующий захваченный вывод обычно отображается вместе с трассировкой ошибки. (Это поведение можно настроить с помощью параметра командной строки --show-capture).
Кроме того, stdin устанавливается в «нулевой» объект, чтение из которого приводит к ошибке, поскольку при запуске автоматизированных тестов обычно нет необходимости ждать ввода от пользователя.
По умолчанию захват выполняется путём перехвата записей на низкоуровневые файловые дескрипторы. Это позволяет захватывать вывод как простых инструкций print, так и подпроцесса, запущенного тестом.
Настройка методов захвата или отключение захвата
pytest может выполнять захват тремя способами:
-
Захват на уровне
fd(файлового дескриптора; используется по умолчанию): захватываются все записи, направленные операционной системе через файловые дескрипторы 1 и 2. -
Захват на уровне
sys: захватываются только записи в файлы Pythonsys.stdoutиsys.stderr. Записи в файловые дескрипторы не захватываются. -
Захват
tee-sys: записи Python вsys.stdoutиsys.stderrзахватываются, но одновременно передаются в настоящиеsys.stdoutиsys.stderr. Это позволяет выводить данные в реальном времени и одновременно захватывать их для использования плагинами, например junitxml (нововведение в pytest 5.4).
Механизмы захвата вывода можно настроить из командной строки:
pytest -s # disable all capturing
pytest --capture=sys # replace sys.stdout/stderr with in-mem files
pytest --capture=fd # also point filedescriptors 1 and 2 to temp file
pytest --capture=tee-sys # combines 'sys' and '-s', capturing sys.stdout/stderr
# and passing it along to the actual sys.stdout/stderr
Отладка с помощью инструкций print
Одно из главных преимуществ захвата вывода stdout/stderr по умолчанию — возможность использовать инструкции print для отладки:
# content of test_module.py
def setup_function(function):
print("setting up", function)
def test_func1():
assert True
def test_func2():
assert False
При запуске этого модуля будет показан именно вывод функции, завершившейся с ошибкой, а вывод другой функции будет скрыт:
$ pytest
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-9.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
collected 2 items
test_module.py .F [100%]
================================= FAILURES =================================
________________________________ test_func2 ________________________________
def test_func2():
> assert False
E assert False
test_module.py:12: AssertionError
-------------------------- Captured stdout setup ---------------------------
setting up <function test_func2 at 0xdeadbeef0001>
========================= short test summary info ==========================
FAILED test_module.py::test_func2 - assert False
======================= 1 failed, 1 passed in 0.12s ========================
Доступ к захваченному выводу из тестовой функции
Фикстуры capsys, capteesys, capsysbinary, capfd и capfdbinary позволяют получить доступ к выводу stdout/stderr, созданному во время выполнения теста.
Вот пример тестовой функции, которая выполняет несколько проверок вывода:
def test_myoutput(capsys): # or use "capfd" for fd-level
print("hello")
sys.stderr.write("world\n")
captured = capsys.readouterr()
assert captured.out == "hello\n"
assert captured.err == "world\n"
print("next")
captured = capsys.readouterr()
assert captured.out == "next\n"
Вызов readouterr() сохраняет снимок вывода на текущий момент, после чего захват продолжается. По завершении тестовой функции исходные потоки восстанавливаются. Использование capsys таким образом избавляет тест от необходимости заботиться о настройке и сбросе потоков вывода и также хорошо взаимодействует с собственным захватом pytest для каждого теста.
Возвращаемое значение readouterr() — это namedtuple с двумя атрибутами: out и err.
Если тестируемый код записывает нетекстовые данные (bytes), их можно захватить с помощью фикстуры capsysbinary, которая вместо этого возвращает bytes из метода readouterr.
Для захвата на уровне файловых дескрипторов можно использовать фикстуру capfd. Она предоставляет тот же интерфейс, но также позволяет захватывать вывод библиотек или подпроцессов, которые напрямую записывают данные в выходные потоки операционной системы (FD1 и FD2). Аналогично capsysbinary, фикстуру capfdbinary можно использовать для захвата bytes на уровне файловых дескрипторов.
Чтобы временно отключить захват в тесте, у фикстур захвата есть метод disabled(), который можно использовать как менеджер контекста. Внутри блока with захват будет отключён:
def test_disabling_capturing(capsys):
print("this output is captured")
with capsys.disabled():
print("output not captured, going directly to sys.stdout")
print("this output is also captured")
Примечание
При использовании фикстуры захвата, такой как capsys или capfd, она имеет приоритет над глобальной настройкой захвата, заданной параметрами командной строки, такими как -s или --capture=no.
Это означает, что вывод, созданный в тесте с использованием фикстуры захвата, всё равно будет захвачен и доступен через readouterr(), даже если глобальный захват отключён.
© 2015–2026 Holger Krekel and pytest-dev team
Licensed under the MIT License.
https://docs.pytest.org/en/stable/how-to/capture-stdout-stderr.html