Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'SentinelObject' object has no attribute 'reset_mock'

I am not sure why the following code is not working. I am using the Mock framework. Anyone could explain it to me?

The error I get is this:

$ python test_mock.py
Calls the mock object method. not a real one. ... ERROR

======================================================================
ERROR: Calls the mock object method. not a real one.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_mock.py", line 37, in test_is_method_called
    self.sut.do_something()
  File "test_mock.py", line 21, in do_something
    self.__obj.method()
  File "build/bdist.linux-i686/egg/mock.py", line 365, in __getattr__
    self._children[name] = self._get_child_mock(parent=self, name=name, wraps=wraps)
  File "build/bdist.linux-i686/egg/mock.py", line 458, in _get_child_mock
    return klass(**kw)
  File "build/bdist.linux-i686/egg/mock.py", line 282, in __init__
    self.reset_mock()
  File "build/bdist.linux-i686/egg/mock.py", line 303, in reset_mock
    self._return_value.reset_mock()
AttributeError: 'SentinelObject' object has no attribute 'reset_mock'

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (errors=1)

The code is:

import unittest
import mock

class Fubar ():

    def __init__(self):
        pass

    def method (self):
        print "I am a Stup!d Monkey!"


class Monkey ():

    def __init__(self, obj):
        self.__obj = obj

    def do_something (self):
        if not isinstance(self.__obj, Fubar):
            raise RuntimeError
        self.__obj.method()


class TestMoneky (unittest.TestCase):

    def setUp(self):
        self.mock_obj = mock.Mock(name="Mock object", spec=["method"])
        self.sut = Monkey(self.mock_obj)

    def tearDown(self):
        pass

    def test_is_method_called (self):
        """Calls the mock object method. not a real one."""
        with mock.patch("__builtin__.isinstance") as mock_inst:
            mock_inst.return_value = True
            self.sut.do_something()
            self.assertTrue(self.mock_obj.method.called)


def main ():
    """Simple runner."""
    suite = unittest.TestSuite()
    suite.addTest(unittest.makeSuite(TestMoneky))
    unittest.TextTestRunner(verbosity=2).run(suite)


if __name__ == '__main__':
    main()
like image 314
Sardathrion - against SE abuse Avatar asked May 13 '26 20:05

Sardathrion - against SE abuse


1 Answers

The problems (sadly) is trivial. I am patching isinstance() to always return True. So, somewhere in the bowels of the module, something is asking whether my mock object is a Sentinel and (since I am overriding the return value), True is returned. Thus the wrong internal behaviour is exhibited.

The solution is therefore to not patch isinstance() but instead provide the mock with a spec that matches the class it is supposed to match:

def setUp(self):
    self.mock_obj = mock.Mock(name="Mock object", spec=Fubar)
    self.sut = Monkey(self.mock_obj)

def test_is_method_called (self):
    """Calls the mock object method. not a real one."""
    self.sut.do_something()
    self.assertTrue(self.mock_obj.method.called)

Can anyone see a way to do this without coupling the mock to Fubar???...

like image 96
Sardathrion - against SE abuse Avatar answered May 15 '26 11:05

Sardathrion - against SE abuse



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!