在 pytest 中,如何暂时禁用 class 方法中的捕获?

In pytest how do I temporarily disable capture in a class method?

在 pytest (3.04; python 3.4) 中,我试图在某些情况下禁用输出捕获。我正在尝试按照 this doc page 上的示例进行操作。但是,我无法将 capsys 指定为 funcarg。作为后续行动,我想同时接受 funcarg 和 on-funcarg 参数,这样我就可以使用带有一个或多个普通参数的 class 方法。我怎样才能做到这一点?

理想情况下,这种 class 方法会起作用:

    def always_print(self, message, capsys):
        with capsys.disabled():
            print(message)

但是,我什至无法让它工作:

def always_print(capsys):
    with capsys.disabled():
        print('FIXME')

获取错误:

...
>       always_print()
E       TypeError: always_print() missing 1 required positional argument: 'capsys'

编辑 1: Piotr 的回答解决了我的具体问题。但是,我还发现了两个我没有在文档或其他帖子中发现的重要警告,因此在这里分享以供他人使用:

  1. 看来 capsys.disabled() 仅适用于 stdout 而 不适用于 stderr,这是我最初根据 *nix 最佳实践发送调试消息的地方。
  2. 如果在 调用 capsys.disabled() 之前将文件句柄设置为 sys.stdout ,那么由于 pytest 执行的魔术文件描述符重整,这不会工作。

所以,例如,你需要这样做(比如,如果你的 kwargs 可能包含一个可选的 "file" 关键字,就像内置的 print() 那样:

 fhandle = kwargs.get('file', sys.stdout) #will not work!
    with capsys.disabled():
        fhandle = kwargs.get('file', sys.stdout) #must be in context
        print(message, file=fhandle)

好吧,capsys 是用于测试的 build-in 夹具。你应该把它作为测试的参数并进一步传递

def always_print(capsys):
    with capsys.disabled():
        print('FIXME')

def test_always_print(capsys):
    always_print(capsys)

如果您使用 pytest 命令 运行 它会起作用。

编辑:

为避免冗长,您可以为所有测试准备一些全局 capsys 变量(基于答案 how to share a variable across modules for all tests in py.test):

# globals.py
capsys = None

# conftest.py
import pytest
import globals as gbl
from _pytest.capture import capsys

@pytest.fixture(autouse=True)
def populate_globals(request):
    gbl.capsys = capsys(request)

# my_tests.py
import globals as gbl

def test_foo():
    with gbl.capsys.disabled():
        print('You can see me')

def test_bar():
    with gbl.capsys.disabled():
        print('You can see me too')