如何在pytest中打印到控制台?


175

我正在尝试将TDD(测试驱动的开发)与 pytestpytest使用时不会print进入控制台print

我正在pytest my_tests.py运行它。

documentation似乎是说,它应该是默认的工作:http://pytest.org/latest/capture.html

但:

import myapplication as tum

class TestBlogger:

    @classmethod
    def setup_class(self):
        self.user = "alice"
        self.b = tum.Blogger(self.user)
        print "This should be printed, but it won't be!"

    def test_inherit(self):
        assert issubclass(tum.Blogger, tum.Site)
        links = self.b.get_links(posts)
        print len(links)   # This won't print either.

什么都没有打印到我的标准输出控制台上(只是正常的进度以及通过/失败的测试数量)。

我正在测试的脚本包含打印:

class Blogger(Site):
    get_links(self, posts):
        print len(posts)   # It won't get printed in the test.

unittest模块中,默认情况下会打印所有内容,这正是我所需要的。但是,我想用pytest出于其他原因。

有谁知道如何使打印报表显示出来?


1
也许stdout被覆盖了。如果使用该sys.stdout.write("Test")怎么办?怎么sys.__stdout__.write("Test")样 后者应始终写入系统定义的标准输出,该标准输出应为控制台。如果这两个命令执行不同的操作,则将更改stdout;否则,将更改标准输出。如果他们做同样的事情,那么问题就出在别的地方。
TheSoundDefense 2014年

Answers:


205

默认情况下,py.test捕获标准输出的结果,以便它可以控制其输出结果的方式。如果不这样做,它将喷出大量文本,而没有测试打印该文本的上下文。

但是,如果测试失败,它将在结果报告中包括一部分,以显示在该特定测试中打印出的标准内容。

例如,

def test_good():
    for i in range(1000):
        print(i)

def test_bad():
    print('this should fail!')
    assert False

结果如下:

>>> py.test tmp.py
============================= test session starts ==============================
platform darwin -- Python 2.7.6 -- py-1.4.20 -- pytest-2.5.2
plugins: cache, cov, pep8, xdist
collected 2 items

tmp.py .F

=================================== FAILURES ===================================
___________________________________ test_bad ___________________________________

    def test_bad():
        print('this should fail!')
>       assert False
E       assert False

tmp.py:7: AssertionError
------------------------------- Captured stdout --------------------------------
this should fail!
====================== 1 failed, 1 passed in 0.04 seconds ======================

注意该Captured stdout部分。

如果您希望print在执行语句时看到它们,可以将-s标志传递给py.test。但是,请注意,有时可能很难解析。

>>> py.test tmp.py -s
============================= test session starts ==============================
platform darwin -- Python 2.7.6 -- py-1.4.20 -- pytest-2.5.2
plugins: cache, cov, pep8, xdist
collected 2 items

tmp.py 0
1
2
3
... and so on ...
997
998
999
.this should fail!
F

=================================== FAILURES ===================================
___________________________________ test_bad ___________________________________

    def test_bad():
        print('this should fail!')
>       assert False
E       assert False

tmp.py:7: AssertionError
====================== 1 failed, 1 passed in 0.02 seconds ======================

2
非常实用。很好!
cmc

1
嗯...仍然没有记录我的打印声明
Tim Boland

68

using -s选项将打印所有功能的输出,可能太多了。

如果您需要特定的输出,则您提到的文档页面提供了一些建议:

  1. assert False, "dumb assert to make PyTest print my stuff"在函数的末尾插入,由于测试失败,您将看到输出。

  2. 您有PyTest传递给您的特殊对象,您可以将输出写入文件中以供日后检查,例如

    def test_good1(capsys):
        for i in range(5):
            print i
        out, err = capsys.readouterr()
        open("err.txt", "w").write(err)
        open("out.txt", "w").write(out)

    您可以在单独的标签中打开outerr文件,然后让编辑器为您自动刷新它,或者执行简单的py.test; cat out.txtshell命令来运行测试。

那是做事的一种骇人听闻的方式,但是可能正是您所需要的东西:毕竟,TDD意味着您会弄乱这些东西,并在准备就绪时保持干净整洁:-)。


我用pytest 3.8.1尝试了版本1。不幸的是,它仅打印测试功能块,而不打印print语句的输出:(为此还有其他技巧吗?
UV

@UV -而不是使用的print()功能,你应该把你的意思是打印的变量或消息 后,在断言语句中的逗号。例如,assert False, what_are_you将“打印” what_are_youpytest报告中的值。
Mart Van de Ven

43

简短答案

使用-s选项:

pytest -s

详细答案

文档

在执行测试期间,将捕获发送到stdoutstderr的所有输出。如果测试或设置方法失败,则通常会显示其相应的捕获输出以及失败回溯。

pytest具有选项--capture=method,其中method是每个测试捕获方法,并且可以是下列之一:fdsysnopytest还具有-s是的快捷方式--capture=no的选项,该选项使您可以在控制台中查看打印语句。

pytest --capture=no     # show print statements in console
pytest -s               # equivalent to previous command

设置捕获方法或禁用捕获

有两种pytest执行捕获的方法:

  1. 文件描述符(FD)级别捕获(默认):将捕获所有对操作系统文件描述符1和2的写操作。

  2. sys级捕获:仅捕获对Python文件sys.stdout和sys.stderr的写入。不捕获对文件描述符的写入。

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

17

PyTest确实需要在忽略所有内容时打印有关跳过测试的重要警告。

我不想通过测试发送信号失败,所以我做了如下的修改:

def test_2_YellAboutBrokenAndMutedTests():
    import atexit
    def report():
        print C_patch.tidy_text("""
In silent mode PyTest breaks low level stream structure I work with, so
I cannot test if my functionality work fine. I skipped corresponding tests.
Run `py.test -s` to make sure everything is tested.""")
    if sys.stdout != sys.__stdout__:
        atexit.register(report)

atexit模块允许我 PyTest释放输出流打印内容。输出如下:

============================= test session starts ==============================
platform linux2 -- Python 2.7.3, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
rootdir: /media/Storage/henaro/smyth/Alchemist2-git/sources/C_patch, inifile: 
collected 15 items 

test_C_patch.py .....ssss....s.

===================== 10 passed, 5 skipped in 0.15 seconds =====================
In silent mode PyTest breaks low level stream structure I work with, so
I cannot test if my functionality work fine. I skipped corresponding tests.
Run `py.test -s` to make sure everything is tested.
~/.../sources/C_patch$

即使PyTest在静默模式下,消息也会被打印,如果您使用来运行东西,则消息不会被打印py.test -s,因此一切都已经过了很好的测试。


1
非常适合输出自定义测试指标。
z0r


2

我最初是来这里寻找如何PyTest在VSCode的控制台中运行/调试单元测试的同时进行打印的。这可以通过以下launch.json配置完成。给定.venv虚拟环境文件夹。

    "version": "0.2.0",
    "configurations": [
        {
            "name": "PyTest",
            "type": "python",
            "request": "launch",
            "stopOnEntry": false,
            "pythonPath": "${config:python.pythonPath}",
            "module": "pytest",
            "args": [
                "-sv"
            ],
            "cwd": "${workspaceRoot}",
            "env": {},
            "envFile": "${workspaceRoot}/.venv",
            "debugOptions": [
                "WaitOnAbnormalExit",
                "WaitOnNormalExit",
                "RedirectOutput"
            ]
        }
    ]
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.