如何捕获 stdout/stderr 输出¶
默认 stdout/stderr/stdin 捕获行为¶
在测试执行期间,发送到 stdout
和 stderr
的任何输出都会被捕获。如果测试或设置方法失败,其捕获的相应输出通常会与失败回溯一起显示。(此行为可以通过 --show-capture
命令行选项进行配置)。
此外,stdin
被设置为“空”对象,它会在尝试从中读取时失败,因为在运行自动化测试时很少需要等待交互式输入。
默认情况下,捕获是通过拦截对低级文件描述符的写入来完成的。这允许捕获来自简单 print 语句的输出以及来自测试启动的子进程的输出。
设置捕获方法或禁用捕获¶
有三种方法 pytest
可以执行捕获
fd
(文件描述符)级别捕获(默认):所有写入操作系统文件描述符 1 和 2 的内容都将被捕获。sys
级别捕获:仅写入 Python 文件sys.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-8.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
、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 自己的每个测试捕获很好地交互。
如果您想在文件描述符级别上进行捕获,可以使用 capfd
固定装置,它提供完全相同的界面,但允许捕获直接写入操作系统级别输出流(FD1 和 FD2)的库或子进程的输出。
readouterr
的返回值已更改为具有两个属性的 namedtuple
,即 out
和 err
。
如果被测代码写入非文本数据,您可以使用 capsysbinary
固定装置捕获此数据,该固定装置会从 readouterr
方法返回 bytes
。
如果被测代码写入非文本数据,您可以使用 capfdbinary
固定装置捕获此数据,该固定装置会从 readouterr
方法返回 bytes
。 capfdbinary
固定装置在文件描述符级别上运行。
为了在测试中暂时禁用捕获, capsys
和 capfd
都具有 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")