Mock Python's built in print function

前端 未结 11 1910
醉话见心
醉话见心 2020-12-06 09:10

I\'ve tried

from mock import Mock
import __builtin__

__builtin__.print = Mock()

But that raises a syntax error. I\'ve also tried patching

相关标签:
11条回答
  • 2020-12-06 09:26

    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')
                ]
            )
    
    0 讨论(0)
  • 2020-12-06 09:29

    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!

    0 讨论(0)
  • 2020-12-06 09:30

    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.

    0 讨论(0)
  • 2020-12-06 09:30

    This is a v3 version of @KC's answer.

    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.

    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()
    

    0 讨论(0)
  • 2020-12-06 09:35
    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!")
    
    0 讨论(0)
  • 2020-12-06 09:37

    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()]
    
    0 讨论(0)
提交回复
热议问题