我已经尝试过
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())
我已在我的单元测试中检查了这个解决方案,它按预期工作。希望这能帮助到某人。祝好!
pytest
中不起作用(对于注释中的格式化表示抱歉)。"def test_status(mocker):
mocker_print = mocker.patch("sys.stdout", new_callable=StringIO)
print("yes")
E TypeError: unicode argument expected, got 'str'"
- Yaroslav Nikitenkofrom io import StringIO
。 - FiddleStix这是一个更简单的Python 3解决方案--直接在内置的print
函数上使用unittest.mock
,而不需调整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()]
另一种示例,直接评估args
和kwargs
:
@patch('builtins.print')
def test_print(mocked_print):
print('foo', 'bar', file=sys.stderr)
assert mocked_print.call_args.args == ('foo', 'bar')
assert mocked_print.call_args.kwargs == dict(file=sys.stderr)
printed = '\n'.join(x.args[0] for x in mocked_print.mocks_calls)
- run_the_raceprint
是 Python 2.x 中的一个关键字,如果将其用作属性会引发 SyntaxError 错误。你可以在文件开头使用 from __future__ import print_function
来避免这种错误。
注意:你不能简单地使用 setattr
,因为除非禁用 print
语句,否则你修改后的 print 函数不会被调用。
编辑:你还需要在想要使用修改后的 print
函数的每个文件中都使用 from __future__ import print_function
,否则它会被 print
语句掩盖。
setattr(__builtin__, 'print', Mock())
,然后以某种方式禁用打印语句吗?或者你是指通过导入Python 3的打印函数来禁用它?如果能够完全在测试端上实现而不修改被测试代码,那就太好了。 - aychedeeprint
函数的源文件中,您需要通过导入 Python 3 的 print
函数来禁用它。在 lqc 的方式中使用的 setattr
将无法工作,因为它被 print
语句掩盖了。 - quantumprint
的实际调用? - Yaroslav Nikitenkofrom 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!")
我的版本。
在被测试的程序中(例如: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')
]
)
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
。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')]
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()
在修补程序的整个过程中,模拟标准输出与使用 pdb.set_trace()
不兼容。我注释掉了 with...
,添加了 if True:
以保持缩进,调试了我的脚本,并在修复错误后重新添加了批处理。
#with patch('sys.stdout', new_callable=StringIO) as buffer:
if True:
foo()
...
这个 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')
还可以使用assert_any_call
from unittest.mock import patch, call
@patch('builtins.print')
def test_print(mocked_print):
print('foo')
print()
mocked_print.assert_any_call('foo')