我试过了
from mock import Mock
import __builtin__
__builtin__.print = Mock()
但这会引发语法错误。我也试过像这样修补它
@patch('__builtin__.print')
def test_something_that_performs_lots_of_prints(self, mock_print):
# assert stuff
有没有办法做到这一点?
我试过了
from mock import Mock
import __builtin__
__builtin__.print = Mock()
但这会引发语法错误。我也试过像这样修补它
@patch('__builtin__.print')
def test_something_that_performs_lots_of_prints(self, mock_print):
# assert stuff
有没有办法做到这一点?
我知道已经有一个公认的答案,但是对于这个问题有一个更简单的解决方案 - 在 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()
当然,您也可以使用以下断言:
self.assertEqual("Something\n", mock_stdout.getvalue())
我已经在我的单元测试中检查了这个解决方案,它按预期工作。希望这可以帮助某人。干杯!
unittest.mock
这是一个更简单的 Python 3 解决方案——直接在内置函数上使用更容易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()]
print
是 python 2.x 中的关键字,将其用作属性会引发 SyntaxError。您可以通过from __future__ import print_function
在文件开头使用来避免这种情况。
注意:您不能简单地使用setattr
,因为您修改的打印功能不会被调用,除非该print
语句被禁用。
编辑:您还需要from __future__ import print_function
在每个文件中使用您修改的print
函数,否则它将被print
语句屏蔽。
如果你想坚持使用 2.x 的print
语句而不是 2.x 的print()
函数,你可以模拟你的sys.stdout
。
写一个虚拟的“文件”,大概是这样:
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
此类期望与获取打印数据的写入函数相结合。这个写入函数应该有两个参数:第一个带有“旧标准输出”的最后用于打印,另一个用于数据。
让我们来
def mywrite(sink, data):
sink.write(data.encode("hex"))
为了那个原因。
现在你可以做
import sys
sys.stdout = Writable(sys.stdout, mywrite)
或者你可以做
@Writable.subclass
def mywritable(sink, data)
sink.write(data.encode("hex"))
sys.stdout = mywritable(sys.stdout)
第二个版本有点棘手:它Writable
在装饰器函数的帮助下创建了一个子类,该函数将给定函数转换为新创建的类的方法,并放入给定函数来自的名称中。
之后,您有一个新类,可以使用“旧标准输出”作为参数进行实例化,然后可以替换sys.stdout
。
我的版本。
在测试程序中(例如:)pp.py
:
from __future__ import print_function
def my_func():
print('hello')
在测试程序中:
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')
]
)
from unittest.mock import patch
def greet():
print("Hello World")
@patch('builtins.print')
def test_greet(mock_print):
greet()
mock_print.assert_called_with("Hello World!")
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')]
这是@KC 答案的 v3 版本。
我不想模拟打印,因为我特别想查看整个输出,而不是检查单个调用,因此 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()
在补丁期间,模拟 stdout 与 using 效果不佳pdb.set_trace()
。我注释掉with...
,添加if True:
以保留缩进,调试我的脚本并在修复错误后放回批处理。
#with patch('sys.stdout', new_callable=StringIO) as buffer:
if True:
foo()
...
首先,模块被调用__builtins__
,你不需要导入它。
现在,在 Python 2print
中是关键字,因此您不能直接将其用作属性名称。您可以使用setattr
/getattr
来解决它:
getattr(__builtins__, "print")
另一种选择是使用from __future__ import print_function
which 更改 Python 将模块解析为 Python 3 语法的方式。
正如 lcq 所说,print是一个关键字。所以,想想如果你真的成功地在 Python 2.7.3 下修补/模拟打印,这意味着什么。你会有这样的代码:
print "Hi."
转变为:
<MagicMock id='49489360'> "Hi."
MagicMock 对象不能以这种方式访问,因此您会收到语法错误。
是的。您只能模拟 Python3 打印函数或 sys.stdout。
这个 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')