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

Posted

技术标签:

【中文标题】如何在pytest中打印到控制台?【英文标题】:How to print to console in pytest? 【发布时间】:2014-08-28 08:05:33 【问题描述】:

我正在尝试将 TDD(测试驱动开发)与 pytest 结合使用。 当我使用print 时,pytest 不会将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

有人知道如何显示打印语句吗?

【问题讨论】:

也许标准输出被覆盖了。如果你使用sys.stdout.write("Test") 会发生什么? sys.__stdout__.write("Test") 怎么样?后者应始终写入系统定义的标准输出,它应该是控制台。如果这两个命令做不同的事情,那么标准输出正在改变;如果他们做同样的事情,那么问题就出在其他地方。 【参考方案1】:

默认情况下,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】:

简答

使用-s 选项:

pytest -s

详细解答

来自the docs:

在测试执行期间,任何发送到 stdoutstderr 的输出都会被捕获。如果测试或设置方法失败,其捕获的输出通常会与失败回溯一起显示。

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

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

设置捕获方法或禁用捕获

pytest 可以通过两种方式执行捕获:

    文件描述符 (FD) 级别捕获(默认):将捕获所有写入操作系统文件描述符 1 和 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

【讨论】:

【参考方案3】:

使用-s 选项将打印所有函数的输出,这可能太多了。

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

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

    你有 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 shell 命令来运行您的测试。

这是一种相当老套的做事方式,但可能正是你需要的东西:毕竟,TDD 意味着你把东西弄乱了,当它准备好时让它保持干净和安静:-)。

【讨论】:

我尝试了版本 1. 使用 pytest 3.8.1 不幸的是它只打印测试功能块,而不是打印语句的输出:( 还有更多技巧吗? @U.V. - 不要使用print() 函数,您应该将要打印的变量或消息放在 逗号之后的断言语句中。例如。 assert False, what_are_you 将在 pytest 报告中“打印出”what_are_you 的值。【参考方案4】:

我需要在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 运行内容,则不会打印消息,因此一切都已经过很好的测试。

【讨论】:

非常适合输出自定义测试指标。【参考方案5】:

这是我所知道的将单个语句打印到 sys.stdout 的最简洁的方式(无需人为地使您的测试失败或启用 -s 选项) - 您可以看到您想要的特定输出,仅此而已:

    将内置参数capsys 添加到您的测试函数中。

    在您的代码中,只需插入:

    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 输出)。

【讨论】:

这应该是首选答案!它似乎完美无缺,没有副作用。 这样我就可以看到我的打印日志了。我没有看到 -s 选项或创建文件的打印日志。【参考方案6】:

根据pytest docs,pytest --capture=sys 应该可以工作。如果您想在测试中捕获标准输出,请参阅 capsys 夹具。

【讨论】:

当终端需要打印变量时,这对我有用... 要在每次运行pytest 时传递--capture 选项,请在文件[pytest][pytest] 部分中添加行addopts = --capture=tee-sys (documentation)。【参考方案7】:

我最初来到这里是为了找到如何在 VSCode 的控制台中打印PyTest,同时从那里运行/调试单元测试。这可以通过以下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"
            ]
        
    ]

【讨论】:

【参考方案8】:

您也可以通过 Pycharm GUI 进行设置:转到 Run > Edit Configurations。在那里,选择您要为其启用打印语句的测试并将-s 添加到Additional Arguments 字段。

我这样做是因为虽然我主要使用 Pycharm 调试器来调试我的 pytest 函数(即通过 GUI),但我的特定用例还要求我知道我的代码中其他地方发生了什么,并且可以打印语句很方便。

【讨论】:

以上是关于如何在pytest中打印到控制台?的主要内容,如果未能解决你的问题,请参考以下文章

pytest日志输出格式

如何查看在 Django 的 manage.py test 命令期间运行了哪些测试

如何在 Python 中将控制台打印到文件中

如何在 iPad 上的 Swift Playgrounds 中打印到控制台?

如何在Travis CI中打印到控制台

如何检查控制台中的笑话覆盖率?