如何捕获stdout和stderr输出

pytest按照命令行参数--capture=或fixture的配置拦截stdout、stderr。--capture=配置报告行为,fixture则提供更细的控制,允许测试过程中检查输出。报告可以通过-r定制。

默认的stdout、stderr和stdin捕获行为

执行测试时,发送到stdout、stderr的输出会被捕获。如果测试或准备方法失败,通常会在失败回溯旁显示相应捕获输出。可用--show-capture命令行选项调整这一行为。

此外,stdin会被设为一个“空”对象,尝试读取它会失败,因为自动测试通常不应等待交互式输入。

默认捕获通过拦截底层文件描述符的写入实现,因此既能捕获普通print语句,也能捕获测试启动的子进程输出。

选择捕获方式或禁用捕获

pytest提供三种捕获方式:

  • fd:文件描述符级捕获,默认方式。 捕获所有写往操作系统文件描述符1和2的内容。
  • sys:Python流级捕获。 只捕获写入Python的sys.stdout、sys.stderr文件对象的内容,不拦截底层文件描述符写入。
  • tee-sys:捕获并透传。 捕获写往sys.stdout、sys.stderr的内容,同时透传到真实的对应流。这样既可实时打印,也能让junitxml等插件使用捕获内容。该方式自pytest5.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()返回一个有out、err两个属性的namedtuple。

如果被测代码写入非文本数据(bytes),可以使用capsysbinary,它的readouterr()返回bytes。

若要在文件描述符级捕获,使用capfd:接口相同,但还能捕获直接写往操作系统输出流FD1、FD2的库或子进程输出。类似地,capfdbinary可以在文件描述符级捕获bytes。

若要在测试中暂时关闭捕获,可将fixture的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等捕获fixture时,fixture优先于-s、--capture=no等命令行全局捕获配置。因此,即使全局关闭捕获,使用捕获fixture的测试输出仍被捕获,可通过readouterr()访问。


来源:How to capture stdout/stderr output,pytest文档。Copyright © 2015, holger krekel and pytest-dev team。完整中文翻译;保留原文示例代码、输出及英文注释,仅调整排版。许可依据:pytest官方许可页。

The MIT License (MIT)

Copyright (c) 2004 Holger Krekel and others

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容