ChatGPT解决这个技术问题 Extra ChatGPT

如何查看 pytest 运行期间创建的正常打印输出?

有时我只想在我的代码中插入一些打印语句,然后看看我在执行它时会打印出什么。我常用的“锻炼”方法是使用现有的 pytest 测试。但是当我运行这些时,我似乎看不到任何标准输出(至少在我的 IDE PyCharm 中)。

有没有一种简单的方法可以在 pytest 运行期间查看标准输出?


v
vinzee

-s switch 禁用每次测试捕获(仅当测试失败时)。

-s 等同于 --capture=no


这会导致输出与 Pytest 输出交错。您可能想要的是 Pytest 像往常一样捕获输出并在测试通过和失败时显示它。请参阅stackoverflow.com/a/59156707/369977
如何在运行过程中看到打印而不等待结束?
如果使用日志记录,另请参阅 stackoverflow.com/questions/4673373/logging-within-pytest-tests 以了解与 -s 一起使用的其他选项
我想知道您所说的“每次测试捕获”是什么意思。我猜,禁用捕获实际上与启用标准输出相同,但我不确定,因为我不知道 pytest 的来龙去脉——我只想看看我的打印语句。你介意详细说明一下吗?
S
Sunthar

pytest 从单个测试中捕获标准输出并仅在某些条件下显示它们,以及默认情况下打印的测试摘要。

Extra summary info 可以使用“-r”选项显示:

pytest -rP

显示已通过测试的捕获输出。

pytest -rx

显示失败测试的捕获输出(默认行为)。

输出的格式使用 -r 比使用 -s 更漂亮。


这是我正在寻找的实际答案!谢谢你。 (需要在测试结果之后出现标准输出。当它们交错时,打印的行会失去价值。)
如何在 Pycharm 中执行此操作(而不是通过命令行)?
@Gulzar 根据此question,您可以执行以下操作:编辑配置 >附加参数 > -r P。我用 Pycharm 2021.1 成功地测试了这一点。在 add'l 参数中的含义是,您输入 -r,然后输入一个空格,然后输入 P。希望有帮助
@spen.smith 这是通过 pycharm 的命令行。我正在寻找内置的东西
pytest -rA 应该打印所有输出。 docs.pytest.org/en/6.2.x/…
u
user229044

在对 accepted answerupvoted comment 中,Joe 问道:

有什么方法可以打印到控制台并捕获输出以便它显示在 junit 报告中?

在 UNIX 中,这通常称为 teeing。理想情况下, py.test 的默认设置是发球而不是捕获。不理想的是,py.test 和任何现有的第三方 py.test 插件(...我知道,无论如何)都不支持 teeing——尽管 Python 微不足道地支持 teeing out-of-the-box

Monkey-patching py.test 做任何不受支持的事情都是不平凡的。为什么?因为:

大多数 py.test 功能被锁定在不打算从外部导入的私有 _pytest 包后面。在不知道自己在做什么的情况下尝试这样做通常会导致公共 pytest 包在运行时引发晦涩的异常。非常感谢,py.test。真正强大的架构,你在那里。

即使您确实知道如何以安全的方式对私有 _pytest API 进行猴子修补,您也必须在运行由外部 py.test 命令运行的公共 pytest 包之前这样做。您不能在插件中执行此操作(例如,测试套件中的顶级 conftest 模块)。当 py.test 懒惰地开始动态导入你的插件时,任何你想要猴子补丁的 py.test 类早就被实例化了——你无法访问那个实例。这意味着,如果您希望有意义地应用猴子补丁,则不能再安全地运行外部 py.test 命令。相反,您必须使用自定义 setuptools 测试命令来包装该命令的运行,该命令(按顺序): Monkey-patches 私有 _pytest API。调用公共 pytest.main() 函数来运行 py.test 命令。

Monkey 修补私有 _pytest API。

调用公共 pytest.main() 函数来运行 py.test 命令。

这个答案猴子补丁 py.test 的 -s--capture=no 选项来捕获 stderr 但 not stdout。默认情况下,这些选项既不捕获标准错误也不捕获标准输出。当然,这并不完全是开球。但每一次伟大的旅程都始于一个乏味的前传,每个人都会在五年内忘记。

为什么要这样做?我现在告诉你。我的 py.test 驱动的测试套件包含缓慢的功能测试。显示这些测试的标准输出是有帮助和令人放心的,防止 leycec 在另一个长时间运行的功能测试连续数周未能执行任何操作时到达 killall -9 py.test。但是,显示这些测试的标准错误会阻止 py.test 报告测试失败的异常回溯。这是完全没有帮助的。因此,我们强制 py.test 捕获 stderr 但 not stdout。

在我们开始之前,这个答案假设您已经有一个自定义 setuptools test 命令调用 py.test。如果您不这样做,请参阅 py.test 编写良好的 Good Practices 页面的 Manual Integration 小节。

不要安装 pytest-runner,这是一个第三方 setuptools 插件,提供自定义 setuptools test 命令也调用 py.test。如果 pytest-runner 已经安装,您可能需要卸载该 pip3 包,然后采用上面链接的手动方法。

假设您按照上面突出显示的 Manual Integration 中的说明进行操作,您的代码库现在应该包含一个 PyTest.run_tests() 方法。将此方法修改为类似于:

class PyTest(TestCommand):
             .
             .
             .
    def run_tests(self):
        # Import the public "pytest" package *BEFORE* the private "_pytest"
        # package. While importation order is typically ignorable, imports can
        # technically have side effects. Tragicomically, that is the case here.
        # Importing the public "pytest" package establishes runtime
        # configuration required by submodules of the private "_pytest" package.
        # The former *MUST* always be imported before the latter. Failing to do
        # so raises obtuse exceptions at runtime... which is bad.
        import pytest
        from _pytest.capture import CaptureManager, FDCapture, MultiCapture

        # If the private method to be monkey-patched no longer exists, py.test
        # is either broken or unsupported. In either case, raise an exception.
        if not hasattr(CaptureManager, '_getcapture'):
            from distutils.errors import DistutilsClassError
            raise DistutilsClassError(
                'Class "pytest.capture.CaptureManager" method _getcapture() '
                'not found. The current version of py.test is either '
                'broken (unlikely) or unsupported (likely).'
            )

        # Old method to be monkey-patched.
        _getcapture_old = CaptureManager._getcapture

        # New method applying this monkey-patch. Note the use of:
        #
        # * "out=False", *NOT* capturing stdout.
        # * "err=True", capturing stderr.
        def _getcapture_new(self, method):
            if method == "no":
                return MultiCapture(
                    out=False, err=True, in_=False, Capture=FDCapture)
            else:
                return _getcapture_old(self, method)

        # Replace the old with the new method.
        CaptureManager._getcapture = _getcapture_new

        # Run py.test with all passed arguments.
        errno = pytest.main(self.pytest_args)
        sys.exit(errno)

要启用此猴子补丁,请按如下方式运行 py.test:

python setup.py test -a "-s"

现在将捕获 Stderr 但不是 stdout。漂亮!

将上面的猴子补丁扩展到 tee stdout 和 stderr 留给读者作为练习,并有大量空闲时间。


pytest 与 --capture=tee-sys docs.pytest.org/en/stable/… 合作
我认为这是第一个让我发笑并且相关的 SO 答案。谢谢 :)
s
slartidan

运行测试时使用 -s 选项。运行测试时,exampletest.py 中的所有打印语句都将打印在控制台上。

py.test exampletest.py -s

这个答案对我有用!
R
Roman Susi

根据 pytest documentation,pytest 版本 3 可以在测试中临时禁用捕获:

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')

a
ankostis

最近添加了 pytest --capture=tee-sys (v5.4.0)。您可以捕获并查看 stdout/err 上的输出。


O
Oleksandr Makarenko

在控制台中尝试 pytest -s -v test_login.py 了解更多信息。

-v 很短--verbose

-s 表示“禁用所有捕获”


如果您使用的是 pytest.ini 文件,您可以使用: addopts = -s -v python_files = test_login.py
如果即使测试通过,您也想打印,这就是我需要的答案。
d
dvvrt

您还可以通过在项目根目录的 pytest.initox.ini 中设置以下内容来启用 live-logging

[pytest]
log_cli = True

或者直接在cli上指定

pytest -o log_cli=True

pytest-5.3.5 上对其进行了测试,并且可以正常工作。您可能还想添加 -s 标志。 pytest -s -o log_cli=True
K
Kiran Sk
pytest test_name.py -v -s

简单的!


V
Vova

我建议使用 -h 命令。可能会使用一些非常有趣的命令。但是,对于这种特殊情况:-s 快捷方式为 --capture=no。足够的

pytest <test_file.py> -s

s
sage

如果您使用 logging,则除了 -s 之外,您还需要指定为通用标准输出打开日志输出。基于 Logging within pytest tests,我正在使用:

pytest --log-cli-level=DEBUG -s my_directory/


G
Gemini Jain

如果您使用的是 PyCharm IDE,那么您可以使用运行工具栏运行单个测试或所有测试。运行工具窗口显示应用程序生成的输出,您可以在其中看到所有打印语句作为测试输出的一部分。


你知道如何在测试运行时打印 PyCharm 吗? (而不是在测试通过之后)
A
Alex Kosh

如果有人想从带有输出的代码运行测试:

if __name__ == '__main__':
    pytest.main(['--capture=no'])

l
lubo

capsys、capsysbinary、capfd 和 capfdbinary 夹具允许访问在测试执行期间创建的 stdout/stderr 输出。这是一个执行一些输出相关检查的示例测试函数:

def test_print_something_even_if_the_test_pass(self, capsys):
    text_to_be_printed = "Print me when the test pass."
    print(text_to_be_printed)
    p_t = capsys.readouterr()
    sys.stdout.write(p_t.out)
    # the two rows above will print the text even if the test pass.

结果如下:

test_print_something_even_if_the_test_pass PASSED [100%]当测试通过时打印我。