1

I have a python file (a.py) which defines a function, and a class which uses it as a default parameter in it's init method and initializes another imported class. This is my a.py

import OtherClass

def useful_default_func():
    //do something useful

class MyClass(object):
    def __init__(self, def_func=useful_default_func):
        self.other_class = OtherClass(def_func())
        //do something useful

I am trying to mock the useful_default_func in my test file.

class TestMyClass(unittest.TestCase):
    @patch('a.useful_default_func')
    @patch('a.OtherClass')
    test_init(self, mock_other_class, mock_default_func):
        myc= MyClass()
        mock_other_class.assert_called_once_with(mock_default_func)
        // further tests

However, the mock_default_func is not patching and my test fails saying,

Expected: OtherClass(<MagicMock id='xxx'>)
Actual: OtherClass(<function useful_default_func at 0x7f155858b378>)

Fairly new to the python mock lib, so not really sure, what is happening here or what I am doing wrong or how should I be approaching it?

saurbh
  • 431
  • 5
  • 13
  • The default parameter is bound when the class is created, *before* you patch. Why not explicitly pass in a mock, given it's parameterised? `myc = MyClass(def_func=mock_default_func)`. – jonrsharpe Mar 22 '20 at 08:29
  • @jonrsharpe I wanted to make sure that no one accidentally changes the default function. Like the default function to the class should always be `useful_default_func` in this case. Maybe there is another way to ensure that or I am not approaching it correctly. – saurbh Mar 24 '20 at 21:30

1 Answers1

1

Something like this could work:

def mocked_fct():
    return 42

class TestMyClass(unittest.TestCase):
    @mock.patch.object(a.MyClass.__init__, '__defaults__', (mocked_fct,))
    @patch('a.OtherClass')
    def test_init(self, mock_other_class):
        myc = MyClass()
        mock_other_class.assert_called_once_with(mocked_fct)

I didn't use a mock for the mocked default function here, this can be changed if needed. The main point is that you can mock the function defaults.

Note: this assumes that you call

self.other_class = OtherClass(def_func)

instead of

self.other_class = OtherClass(def_func())

If this was not a typo, your assertion would not be correct. In this case, you could instead use:

mock_other_class.assert_called_once_with(mocked_fct())
mock_other_class.assert_called_once_with(42)  # same as above
MrBean Bremen
  • 14,916
  • 3
  • 26
  • 46