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

550 投票
12 回答
450053 浏览
提问于 2025-04-18 12:24

当我使用 print 时,pytest 不会在控制台上打印任何内容。看起来 文档 说默认情况下应该可以工作。

我用 pytest my_tests.py 来运行这个测试:

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.

但是我的标准输出控制台上什么都没打印出来(只显示了正常的进度,以及有多少个测试通过或失败)。

而我正在测试的脚本里确实有 print 语句:

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

unittest 模块中,所有内容默认都会打印出来,这正是我需要的。不过,我还是想用 pytest,因为有其他原因。

有没有人知道怎么才能让 print 语句显示出来呢?

12 个回答

20

我需要在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运行测试,这条消息就不会被打印,所以这样一来,所有的测试都能正常进行。

59

这是我知道的最简单的方法,可以把一条信息打印到 sys.stdout 上(而不需要故意让你的测试失败或者开启 -s 选项)——这样你就能看到你想要的具体输出,而不会有其他多余的内容:

  1. 在你的测试函数中添加内置参数 capsys。(这意味着你需要把 capsys 加到参数列表中,比如:
def test_function(existing_parameters, capsys):
  1. 在你的代码中,简单地插入:
with capsys.disabled():
   print("this output will not be captured and go straight to sys.stdout")

详细信息可以查看 https://buildmedia.readthedocs.org/media/pdf/pytest/latest/pytest.pdf(第2.11节 如何捕获stdout/stderr输出)。

115

使用 -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.txt 命令来运行你的测试。

这确实是一种比较“hack”的做法,但也许这正是你需要的:毕竟,测试驱动开发(TDD)就是在搞事情,等准备好了再把它清理干净,让它安静下来 :-).

453

使用 -s 选项:

pytest -s

详细解答

根据 官方文档

在测试执行过程中,任何发送到标准输出(stdout)标准错误(stderr)的内容都会被捕获。如果某个测试或设置方法失败,通常会显示捕获到的输出和失败的追踪信息。

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. 系统级别捕获:只有写入 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
491

默认情况下,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 语句的输出,可以在运行 py.test 时加上 -s 这个选项。不过要注意,这样有时候会让人看得有点费劲。

>>> 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 ======================

撰写回答