简体   繁体   English

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

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

Sometimes I want to just insert some print statements in my code, and see what gets printed out when I exercise it.有时我只想在我的代码中插入一些打印语句,然后看看我在执行它时会打印出什么。 My usual way to "exercise" it is with existing pytest tests.我常用的“锻炼”方法是使用现有的 pytest 测试。 But when I run these, I don't seem able to see any standard output (at least from within PyCharm, my IDE).但是当我运行这些时,我似乎看不到任何标准输出(至少在我的 IDE PyCharm 中)。

Is there a simple way to see standard output during a pytest run?有没有一种简单的方法可以在 pytest 运行期间查看标准输出?

The -s switch disables per-test capturing (only if a test fails). -s开关禁用每次测试捕获(仅当测试失败时)。

-s is equivalent to --capture=no . -s相当于--capture=no

pytest captures the stdout from individual tests and displays them only on certain conditions, along with the summary of the tests it prints by default. pytest 从单个测试中捕获标准输出并仅在某些条件下显示它们,以及默认情况下打印的测试摘要。

Extra summary info can be shown using the '-r' option:可以使用“-r”选项显示额外的摘要信息

pytest -rP

shows the captured output of passed tests.显示已通过测试的捕获输出。

pytest -rx

shows the captured output of failed tests (default behaviour).显示失败测试的捕获输出(默认行为)。

The formatting of the output is prettier with -r than with -s.输出的格式使用 -r 比使用 -s 更漂亮。

In an upvoted comment to the accepted answer , Joe asks:在对已接受答案赞成评论中,问道:

Is there any way to print to the console AND capture the output so that it shows in the junit report?有什么方法可以打印到控制台捕获输出以便它显示在 junit 报告中?

In UNIX, this is commonly referred to as teeing .在 UNIX 中,这通常称为teeing Ideally, teeing rather than capturing would be the py.test default.理想情况下, py.test 的默认设置是发球而不是捕获。 Non-ideally, neither py.test nor any existing third-party py.test plugin (... that I know of, anyway ) supports teeing – despite Python trivially supporting teeing out-of-the-box .非理想情况下,py.test 和任何现有的第三方 py.test 插件(我知道,无论如何)都不支持 teeing——尽管 Python 微不足道地支持 teeing out-of-the-box

Monkey-patching py.test to do anything unsupported is non-trivial. Monkey-patching py.test 做任何不受支持的事情都是不平凡的。 Why?为什么? Because:因为:

  • Most py.test functionality is locked behind a private _pytest package not intended to be externally imported.大多数 py.test 功能被锁定在打算从外部导入的私有_pytest包后面。 Attempting to do so without knowing what you're doing typically results in the public pytest package raising obscure exceptions at runtime.在不知道自己在做什么的情况下尝试这样做通常会导致公共pytest包在运行时引发晦涩的异常。 Thanks alot, py.test.非常感谢,py.test。 Really robust architecture you got there.真正强大的架构,你在那里。
  • Even when you do figure out how to monkey-patch the private _pytest API in a safe manner, you have to do so before running the public pytest package run by the external py.test command.即使您确实知道如何以安全的方式对私有_pytest API 进行猴子修补,您也必须在运行由外部py.test命令运行的公共pytest之前这样做。 You cannot do this in a plugin (eg, a top-level conftest module in your test suite).不能在插件中执行此操作(例如,测试套件中的顶级conftest模块)。 By the time py.test lazily gets around to dynamically importing your plugin, any py.test class you wanted to monkey-patch has long since been instantiated – and you do not have access to that instance.当 py.test 懒惰地开始动态导入你的插件时,任何你想要猴子补丁的 py.test 类早就被实例化了——你无法访问那个实例。 This implies that, if you want your monkey-patch to be meaningfully applied, you can no longer safely run the external py.test command.这意味着,如果您希望有意义地应用猴子补丁,则不能再安全地运行外部py.test命令。 Instead, you have to wrap the running of that command with a custom setuptools test command that (in order):相反,您必须使用自定义 setuptools test命令来包装该命令的运行,该命令(按顺序):
    1. Monkey-patches the private _pytest API. Monkey 修补私有_pytest API。
    2. Calls the public pytest.main() function to run the py.test command.调用公共pytest.main()函数来运行py.test命令。

This answer monkey-patches py.test's -s and --capture=no options to capture stderr but not stdout.这个答案猴子补丁 py.test 的-s--capture=no选项来捕获标准错误而不是标准输出。 By default, these options capture neither stderr nor stdout.默认情况下,这些选项既不捕获标准错误也不捕获标准输出。 This isn't quite teeing, of course.当然,这并不完全是开球。 But every great journey begins with a tedious prequel everyone forgets in five years.但每一次伟大的旅程都始于一个乏味的前传,每个人都会在五年内忘记。

Why do this?为什么要这样做? I shall now tell you.我现在告诉你。 My py.test-driven test suite contains slow functional tests.我的 py.test 驱动的测试套件包含缓慢的功能测试。 Displaying the stdout of these tests is helpful and reassuring, preventing leycec from reaching for killall -9 py.test when yet another long-running functional test fails to do anything for weeks on end.显示这些测试的标准输出是有帮助和令人放心的,当另一个长时间运行的功能测试连续数周都没有做任何事情时,可以防止leycec到达killall -9 py.test Displaying the stderr of these tests, however, prevents py.test from reporting exception tracebacks on test failures.但是,显示这些测试的标准错误会阻止 py.test 报告测试失败的异常回溯。 Which is completely unhelpful.这是完全没有帮助的。 Hence, we coerce py.test to capture stderr but not stdout.因此,我们强制 py.test 捕获 stderr 而不是stdout。

Before we get to it, this answer assumes you already have a custom setuptools test command invoking py.test.在我们开始之前,这个答案假设您已经有一个调用 py.test 的自定义 setuptools test命令。 If you don't, see theManual Integration subsection of py.test's well-written Good Practices page.如果您不这样做,请参阅 py.test 编写良好的良好实践页面的手动集成小节。

Do not install pytest-runner , a third-party setuptools plugin providing a custom setuptools test command also invoking py.test.不要安装pytest-runner ,第三方 setuptools 插件提供自定义 setuptools test命令也调用 py.test。 If pytest-runner is already installed, you'll probably need to uninstall that pip3 package and then adopt the manual approach linked to above.如果 pytest-runner 已经安装,您可能需要卸载该 pip3 包,然后采用上面链接的手动方法。

Assuming you followed the instructions inManual Integration highlighted above, your codebase should now contain a PyTest.run_tests() method.假设您按照上面突出显示的手动集成中的说明进行操作,您的代码库现在应该包含一个PyTest.run_tests()方法。 Modify this method to resemble:将此方法修改为类似于:

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)

To enable this monkey-patch, run py.test as follows:要启用此猴子补丁,请按如下方式运行 py.test:

python setup.py test -a "-s"

Stderr but not stdout will now be captured.现在将捕获 Stderr 但不是stdout。 Nifty!漂亮!

Extending the above monkey-patch to tee stdout and stderr is left as an exercise to the reader with a barrel-full of free time.将上面的猴子补丁扩展到 tee stdout 和 stderr 留给读者作为练习,并有大量空闲时间。

When running the test use the -s option.运行测试时使用-s选项。 All print statements in exampletest.py would get printed on the console when test is run.运行测试时, exampletest.py中的所有打印语句都将打印在控制台上。

py.test exampletest.py -s

According to pytest documentation , version 3 of pytest can temporary disable capture in a test:根据pytest 文档,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')

pytest --capture=tee-sys was recently added ( v5.4.0 ).最近添加了pytest --capture=tee-sys ( v5.4.0 )。 You can capture as well as see the output on stdout/err.您可以捕获并查看 stdout/err 上的输出。


Try pytest -s -v test_login.py for more info in console.尝试pytest -s -v test_login.py在控制台中获取更多信息。

-v it's a short --verbose -v这是一个简短的--verbose

-s means 'disable all capturing' -s表示“禁用所有捕获”



You can also enable live-logging by setting the following in pytest.ini or tox.ini in your project root.您还可以通过在项目根目录中的pytest.initox.ini中设置以下内容来启用实时日志记录

[pytest]
log_cli = True

Or specify it directly on cli或者直接在cli上指定

pytest -o log_cli=True
pytest test_name.py -v -s

简单的!

I would suggest using -h command.我建议使用 -h 命令。 There're quite interesting commands might be used for.可能会使用一些非常有趣的命令。 but, for this particular case: -s shortcut for --capture=no.但是,对于这种特殊情况: -s快捷方式为 --capture=no。 is enough足够的

pytest <test_file.py> -s

If you are using PyCharm IDE, then you can run that individual test or all tests using Run toolbar.如果您使用的是 PyCharm IDE,那么您可以使用运行工具栏运行单个测试或所有测试。 The Run tool window displays output generated by your application and you can see all the print statements in there as part of test output.运行工具窗口显示应用程序生成的输出,您可以在其中看到所有打印语句作为测试输出的一部分。

If you are using logging , you need to specify to turn on logging output in addition to -s for generic stdout.如果您使用logging ,除了-s用于通用标准输出之外,您还需要指定打开日志输出。 Based on Logging within pytest tests , I am using:基于pytest 测试中的日志记录,我正在使用:

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

If anyone wants to run tests from code with output:如果有人想从带有输出的代码运行测试:

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

The capsys, capsysbinary, capfd, and capfdbinary fixtures allow access to stdout/stderr output created during test execution. capsys、capsysbinary、capfd 和 capfdbinary 夹具允许访问在测试执行期间创建的 stdout/stderr 输出。 Here is an example test function that performs some output related checks:这是一个执行一些输出相关检查的示例测试函数:

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.

Here is the result:结果如下:

test_print_something_even_if_the_test_pass PASSED [100%]Print me when the test pass. test_print_something_even_if_the_test_pass PASSED [100%]当测试通过时打印我。

The other answers don't work. 其他答案不起作用。 The only way to see the captured output is using the following flag: 查看捕获的输出的唯一方法是使用以下标志:

pytest --show-capture all pytest - 显示全部捕获

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM