关于python:如何在pytest运行期间看到正常的打印输出?

How can I see normal print output created during pytest run?

有时,我只想在代码中插入一些打印语句,看看当我练习它时会打印出什么。我通常的"练习"方法是使用现有的Pytest测试。但当我运行这些程序时,我似乎看不到任何标准输出(至少在我的IDE pycharm中是这样)。

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


-s开关禁用每次测试捕获。


在对已接受答案的乐观评论中,乔问:

Is there any way to print to the console AND capture the output so that it shows in the junit report?

在Unix中,这通常被称为teeing。理想情况下,teeing而不是捕获将是py.test的默认值。非理想情况下,py.test和任何现有的第三方py.test插件(我知道,无论如何)都不支持teeing——尽管python非常支持现成的teeing。

猴子修补py.test来做任何不支持的事情都是不平凡的。为什么?因为:

  • 大多数py.test功能都锁定在不打算从外部导入的私有_pytest包之后。尝试在不知道自己在做什么的情况下这样做通常会导致公共的pytest包在运行时引发一些模糊的异常。多谢,小派。测试。你的架构非常强大。
  • 即使您确实知道如何安全地对私有_pytestAPI进行monkey修补,也必须在运行由外部py.test命令运行的公共pytest包之前进行。您不能在插件(例如,测试套件中的顶级conftest模块)中执行此操作。当py.test懒散地开始动态导入插件时,任何你想要安装monkey补丁的py.test类都已经被实例化了——你没有访问该实例的权限。这意味着,如果您希望有意义地应用monkey补丁,就不能再安全地运行外部py.test命令。相反,您必须用一个定制的SETUPTOOLS test命令来包装该命令的运行,该命令(按顺序)如下:
  • monkey补丁私有_pytestAPI。
  • 调用public pytest.main()函数来运行py.test命令。

这个答案是monkey补丁py.test的-s--capture=no选项来捕获stderr而不是stdout。默认情况下,这些选项既不捕获stderr也不捕获stdout。当然,这不是很容易上牙。但是每一次伟大的旅程都是以一个五年后每个人都会忘记的乏味前传开始的。

为什么这么做?我现在就告诉你。我的py.test-driven测试套件包含缓慢的功能测试。显示这些测试中的stdout是有益且可靠的,防止leycec在另一个长时间运行的功能测试连续数周没有做任何事情的时候达到killall -9 py.test。但是,显示这些测试的stderr会阻止py.test报告测试失败的异常跟踪。这完全没用。因此,我们强制py.test捕获stderr,而不是stdout。

在我们开始之前,这个答案假设您已经有了一个自定义的设置工具test命令来调用py.test。如果不这样做,请参见py.test编写良好的良好实践页面的手动集成小节。

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

假设您遵循上面强调的手动集成中的说明,那么您的代码库现在应该包含一个PyTest.run_tests()方法。将此方法修改为类似:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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)

要启用此monkey补丁,请运行py.test,如下所示:

1
python setup.py test -a"-s"

现在将捕获stderr而不是stdout。漂亮!

把上面的monkey补丁扩展到tee stdout和stderr,留给读者做一个充满空闲时间的练习。


根据Pytest文档,Pytest版本3可以临时禁用测试中的捕获:

1
2
3
4
5
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')

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

1
py.test exampletest.py -s

有关控制台中的更多信息,请尝试使用pytest -s -v test_login.py

-v是一个短的--verbose

-s表示"禁用所有捕获"


1
2
3
4
5
pytest -v -s scriptname(for single test script)

pytest -v -s (for complete module/package)

pytest -v -s scriptname::function(indiviual function)


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