本文翻译自: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). 但是当我运行这些时,我似乎无法看到任何标准输出(至少来自PyCharm,我的IDE)。
Is there a simple way to see standard output during a pytest run? 在pytest运行期间有没有一种简单的方法来查看标准输出?
参考:https://stackoom.com/question/yRPj/如何查看pytest运行期间创建的正常打印输出
-s
开关禁用每次测试捕获。
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
所有print语句exampletest.py
将打印在控制台上。
py.test exampletest.py -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. 理想情况下,teeing而不是捕获将是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插件( 我知道,无论如何 ) 都不支持发球 - 尽管Python平凡地支持开箱即用的发球。
Monkey-patching py.test to do anything unsupported is non-trivial. 猴子修补py.test做任何不受支持的事情都是非平凡的。 Why? 为什么? Because: 因为:
_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. 你到那里真的很健壮的建筑。 _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,你必须运行在公众面前这样做pytest
包由外部运行py.test
命令。 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. 这意味着,如果您希望有意义地应用您的monkey-patch,则无法再安全地运行外部py.test
命令。 Instead, you have to wrap the running of that command with a custom setuptools test
command that (in order): 相反,您必须使用自定义setuptools test
命令(按顺序)包装该命令的运行:
_pytest
API. Monkey-patches私有_pytest
API。 pytest.main()
function to run the py.test
command. 调用public 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
选项来捕获stderr而不是 stdout。 By default, these options capture neither stderr nor stdout. 默认情况下,这些选项既不捕获stderr也不捕获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. 但是,显示这些测试的stderr会阻止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. 在我们开始之前,这个答案假设您已经有一个自定义setuptools test
命令来调用py.test。 If you don't, see the Manual 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亚军 ,第三方插件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 in Manual 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: 要启用此monkey-patch,请运行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,留给玩家一个充满空闲时间的练习。
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')
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
表示'禁用所有捕获'