模拟 Python 的内置打印功能
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12998908/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Mock Python's built in print function
提问by aychedee
I've tried
我试过了
from mock import Mock
import __builtin__
__builtin__.print = Mock()
But that raises a syntax error. I've also tried patching it like so
但这会引发语法错误。我也试过像这样修补它
@patch('__builtin__.print')
def test_something_that_performs_lots_of_prints(self, mock_print):
# assert stuff
Is there any way to do this?
有没有办法做到这一点?
采纳答案by quantum
printis a keyword in python 2.x, using it as attribute raises a SyntaxError. You can avoid that by using from __future__ import print_functionin the beginning of the file.
print是 python 2.x 中的关键字,将其用作属性会引发 SyntaxError。您可以通过from __future__ import print_function在文件开头使用来避免这种情况。
Note: you can't simply use setattr, because the print function you modified doesn't get invoked unless the printstatement is disabled.
注意:您不能简单地使用setattr,因为除非print禁用该语句,否则不会调用您修改的打印函数。
Edit: you also need to from __future__ import print_functionin every file you want your modified printfunction to be used, or it will be masked by the printstatement.
编辑:您还需要from __future__ import print_function在您希望print使用修改后的函数的每个文件中,否则它将被print语句屏蔽。
回答by lqc
First, the module is called __builtins__and you don't need to import it.
首先,模块被调用__builtins__,您不需要导入它。
Now, in Python 2 printis a keyword so you can't use it as an attribute name directly. You can use setattr/getattrto workaround it:
现在,在 Python 2 中print是一个关键字,因此您不能直接将其用作属性名称。您可以使用setattr/getattr来解决它:
getattr(__builtins__, "print")
Another option is to use from __future__ import print_functionwhich changes how Python parses the module to Python 3 syntax.
另一种选择是使用from __future__ import print_functionwhich 将 Python 解析模块的方式更改为 Python 3 语法。
回答by glglgl
If you want to stick with the printstatement from 2.x as opposed to the print()function from 2.x, you could mock your sys.stdoutinstead.
如果你想坚持使用print2.x 中的语句而不是 2.x 中的print()函数,你可以模拟你的sys.stdout。
Write a dummy "file", perhaps in about this way:
写一个虚拟的“文件”,大概是这样的:
class Writable(object):
"""Class which has the capability to replace stdout."""
newwrite = None
def __init__(self, oldstdout, newwrite=None):
self.oldstdout = oldstdout
if newwrite is not None:
self.newwrite = newwrite
def write(self, data):
self.newwrite(self.oldstdout, data)
@classmethod
def subclass(cls, writefunc):
newcls = type('', (cls,),
dict(write=lambda self, data: writefunc(self.oldstdout, data)
return newcls
This class expects to be combined with a writing function which gets the printed data. This writing function is supposed to take 2 arguments: the first one with the "old stdout" to be used for printing at the end, and a further one for the data.
此类期望与获取打印数据的写入函数结合使用。这个写入函数应该有 2 个参数:第一个带有用于最后打印的“旧标准输出”,另一个用于数据。
Let's take
让我们来
def mywrite(sink, data):
sink.write(data.encode("hex"))
for that.
为了那个原因。
Now you can do
现在你可以做
import sys
sys.stdout = Writable(sys.stdout, mywrite)
or you can do
或者你可以做
@Writable.subclass
def mywritable(sink, data)
sink.write(data.encode("hex"))
sys.stdout = mywritable(sys.stdout)
The 2nd version is a bit trickier: it creates a subclass of the Writablewith the help of a decorator function which turns the given function into a method of the new class created instead and put into the name where the given function comes from.
第二个版本有点棘手:它Writable在装饰器函数的帮助下创建了 的子类,该函数将给定的函数转换为所创建的新类的方法,并将其放入给定函数的名称中。
After that, you have a new class which can be instantiated with the "old stdout" as argument and can replace sys.stdoutafter that.
之后,您有一个新类,可以使用“旧标准输出”作为参数进行实例化,然后可以替换sys.stdout。
回答by dbn
As lcq says, printis a keyword. So, think about what it would mean if you were actually successful in patching/mocking print under Python 2.7.3. You would have code like this:
正如 lcq 所说,print是一个关键字。所以,想想如果你在 Python 2.7.3 下真正成功地修补/模拟打印,这意味着什么。你会有这样的代码:
print "Hi."
turning into:
转变为:
<MagicMock id='49489360'> "Hi."
MagicMock objects cannot be accessed this way, so you would get a syntax error.
无法通过这种方式访问 MagicMock 对象,因此您会收到语法错误。
So... Yeah. You can only mock the Python3 print functionor sys.stdout.
是的。您只能模拟 Python3 打印函数或 sys.stdout。
回答by Chien-Wei Huang
My version.
我的版本。
In the tested program(ex: pp.py):
在测试程序中(例如:)pp.py:
from __future__ import print_function
def my_func():
print('hello')
In the test program:
在测试程序中:
def test_print(self):
from pp import my_func
from mock import call
with mock.patch('__builtin__.print') as mock_print:
my_func()
mock_print.assert_has_calls(
[
call('hello')
]
)
回答by sgjurano
import mock
import sys
mock_stdout = mock.Mock()
sys.stdout = mock_stdout
print 'Hello!'
sys.stdout = sys.__stdout__
print mock_stdout.mock_calls
[call.write('Hello!'), call.write('\n')]
回答by Krzysztof Czeronko
I know that there is already an accepted answer but there is simpler solution for that problem - mocking the print in python 2.x. Answer is in the mock library tutorial: http://www.voidspace.org.uk/python/mock/patch.htmland it is:
我知道已经有一个可以接受的答案,但有一个更简单的解决方案 - 在 python 2.x 中模拟打印。答案在模拟库教程中:http: //www.voidspace.org.uk/python/mock/patch.html,它是:
>>> from StringIO import StringIO
>>> def foo():
... print 'Something'
...
>>> @patch('sys.stdout', new_callable=StringIO)
... def test(mock_stdout):
... foo()
... assert mock_stdout.getvalue() == 'Something\n'
...
>>> test()
Of course you can use also following assertion:
当然,您也可以使用以下断言:
self.assertEqual("Something\n", mock_stdout.getvalue())
I have checked this solution in my unittests and it is working as expected. Hope this helps somebody. Cheers!
我已经在我的单元测试中检查了这个解决方案,它按预期工作。希望这可以帮助某人。干杯!
回答by Acumenus
This Python 3 example builds upon the Python 2 answer by Krzysztof. It uses unittest.mock. It uses a reusable helper method for making the assertion.
这个 Python 3 示例建立在 Krzysztof 的 Python 2 答案之上。它使用unittest.mock. 它使用可重用的辅助方法进行断言。
import io
import unittest
import unittest.mock
from .solution import fizzbuzz
class TestFizzBuzz(unittest.TestCase):
@unittest.mock.patch('sys.stdout', new_callable=io.StringIO)
def assert_stdout(self, n, expected_output, mock_stdout):
fizzbuzz(n)
self.assertEqual(mock_stdout.getvalue(), expected_output)
def test_only_numbers(self):
self.assert_stdout(2, '1\n2\n')
回答by Tom
This is a much simpler Python 3 solution -- it's easier to use unittest.mockdirectly on the builtin printfunction, rather than fiddling around with sys.stdout:
这是一个更简单的 Python 3 解决方案——unittest.mock直接在内置print函数上使用更容易,而不是摆弄sys.stdout:
from unittest.mock import patch, call
@patch('builtins.print')
def test_print(mocked_print):
print('foo')
print()
assert mocked_print.mock_calls == [call('foo'), call()]
回答by JL Peyret
This is a v3 version of @KC's answer.
这是@KC 答案的 v3 版本。
I didn't want to mock print because I specifically wanted to see the output as a whole, not check out individual calls so StringIO makes more sense to me.
我不想模拟打印,因为我特别想查看整个输出,而不是查看单个调用,因此 StringIO 对我来说更有意义。
from io import StringIO
from unittest.mock import patch
def foo():
print ('Something')
def test():
with patch('sys.stdout', new_callable=StringIO) as buffer:
foo()
fake_stdout = buffer.getvalue()
#print() is back!
print(f"fake_stdout:{fake_stdout}")
assert fake_stdout == 'Something\n'
test()
warning:
警告:
for the duration of the patch, mocking stdout plays badly with using pdb.set_trace(). I commented out with..., added if True:to keep the indentation, debugged my script and put back the batch once I fixed my error.
在补丁期间,模拟标准输出在使用pdb.set_trace(). 我注释掉with...,添加if True:以保持缩进,调试我的脚本并在我修复错误后放回批处理。
#with patch('sys.stdout', new_callable=StringIO) as buffer:
if True:
foo()
...

