SentinelObject'对象没有'reset_mock'属性

2 投票
1 回答
1660 浏览
提问于 2025-04-17 06:49

我不太明白为什么下面的代码不管用。我正在使用Mock框架。有人能给我解释一下吗?

我遇到的错误是:

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

代码是:

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

1 个回答

4

问题其实很简单。我的做法是把 isinstance() 这个函数改成总是返回 True。所以在模块的某个地方,有东西在检查我的模拟对象是不是一个 Sentinel(哨兵对象),因为我改了返回值,所以它返回了 True。这就导致了内部行为不对劲。

解决办法就是不要改 isinstance(),而是给模拟对象提供一个和它应该匹配的类相符的规格:

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)

有没有人能想到一种方法来做到这一点,而不把模拟对象和 Fubar 绑定在一起???...

撰写回答