Python mock: patching

From wikinotes

mock.patch

Patching allows you to target a specific function by it's module-path.

import unittest
import mock
 
class Test_First(unittest.TestCase):
    def test_myotherfunc_wascalled(self):
        with mock.patch( 'os.path.isfile', return_value=True ) as _mock_myotherfunc:
            ClassImTesting()

mock.patch.object

with mock.patch.object(os.path, 'isfile', return_value=True):
    os.path.isfile('/not/a/file')

mock.patch.dict

with mock.patch.dict('os.environ', {'TEST': '1'}):
   os.environ['TEST']


decorator

In order to avoid nesting with mock.patch statements
(and indenting to infinity), you can use a decorator on your unittest,
then modify your mock object's attributes for return-values etc.
This method of mocking is much more readable when things get very complex.

class TestExample(unittest.TestCase):
    @mock.patch('os.path')
    @mock.patch('os.stat')
    def test_patching(self, mock_stat, mock_path):
        os.path.return_value = True
        ClassImTesting()

mock a class and multiple methods

Only mock methods, leaving class intact.

with mock.patch.object(MyClass, 'methodA', return_value='a'):
    with mock.patch.object(MyClass, 'methodB', return_value='b'):
        MyClass().methodA()
        MyClass().methodB()

Mock entire class, and modify methods.

def test_myclass():
    ns = myclass.__name__
    with mock.patch( '{}.MyClass'.format(ns) ) as mock_myclass:
        # method A
        mock_mycls.return_value.do_something = mock.Mock(return_value='new return!')

        # method B
        mock_mycls().do_something = mock.Mock(return_value='new_return')

https://stackoverflow.com/questions/41627576/python-mock-patch-multiple-methods-in-a-class

mock any instance of a class

@mock.patch('foo.Bar')
def test_something(self, m_cls):
    m_inst = mock.Mock()
    m_cls.return_value = m_inst

    m_inst.start.assert_called_with('cat')

mock a context-manager

The trick is to mock `__enter__` , and it's return value.

with mock.patch('zipfile.ZipFile') as mock_zip:
    mock_ziparchive = mock.Mock()
    mock_ziparchive.return_value.namelist.return_value = ['a/b.txt']

    mock_zip.return_value.__enter__ = mock_ziparchive

will mock the following

with zipfile.ZipFile('a/b.zip', 'r') as archive:
    print(archive.namelist())

>>> ['a/b.txt']


mock attribute

getmodules = mock.PropertyMock(return_value={})
with mock.patch.object(sys, 'modules', new_callable=getmodules):
    print(sys.modules)

mock import

Mocking imports depends on the style of import.

  • from X import Y imports attribute Y from the mock object X
  • import X.Y imports Y directly


# from maya import cmds
maya_cmds = mock.MagicMock()
maya_cmds.about = mock.Mock(return_value='2015')

maya = mock.MagicMock()
maya.cmds = maya_cmds
sys.modules['maya'] = mock_maya
# import maya.cmds
maya_cmds = mock.Mock()
maya_cmds.about = mock.Mock(returnvalue='2015')
sys.modules['maya.cmds'] = mock_maya_cmds