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?
print
is a keyword in python 2.x, using it as attribute raises a SyntaxError. You can avoid that by using from __future__ import print_function
in the beginning of the file.
Note: you can't simply use setattr
, because the print function you modified doesn't get invoked unless the print
statement is disabled.
Edit: you also need to from __future__ import print_function
in every file you want your modified print
function to be used, or it will be masked by the print
statement.
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.html and it is:
>>> 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!
This is a much simpler Python 3 solution -- it's easier to use unittest.mock
directly on the builtin print
function, rather than fiddling around with 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()]
If you want to stick with the print
statement from 2.x as opposed to the print()
function from 2.x, you could mock your sys.stdout
instead.
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.
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 Writable
with 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.
After that, you have a new class which can be instantiated with the "old stdout" as argument and can replace sys.stdout
after that.
My version.
In the tested program(ex: 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')
]
)
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')]
First, the module is called __builtins__
and you don't need to import it.
Now, in Python 2 print
is a keyword so you can't use it as an attribute name directly. You can use setattr
/getattr
to workaround it:
getattr(__builtins__, "print")
Another option is to use from __future__ import print_function
which changes how Python parses the module to Python 3 syntax.
As lcq says, print is 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:
print "Hi."
turning into:
<MagicMock id='49489360'> "Hi."
MagicMock objects cannot be accessed this way, so you would get a syntax error.
So... Yeah. You can only mock the Python3 print function or sys.stdout.
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.
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')
来源:https://stackoverflow.com/questions/12998908/mock-pythons-built-in-print-function