简体   繁体   中英

Raise error when calling a non-existent method of a mocked method of a mock created from `spec`

from unittest import mock
class A:
    def f(self): pass
m = mock.MagicMock(spec_set=A)
m.f.called_once()  # I want this to fail
Out[42]: <MagicMock name='mock.f.called_once()' id='140326790593792'>

I have made a mistake in my unit test and called called_once instead of assert_called_once on a mocked method. The call results in a new MagicMock instance, so the test was passing and not checking what I inteneded to check -- if the method was invoked. Is there a way to make mock fail if the method is not defined, when the mock is created from spec_set ? It's like I want spec_set to be applied all the way down to the method mocks themselves.

Use create_autospec :

from unittest import mock
class A:
    def f(self): pass
m = mock.create_autospec(A)
m.f()
m.f.assert_called_once()  # works OK
m.f.misstyped_called_once() # raises
Traceback (most recent call last):
  File "/Users/ant/opt/miniconda3/envs/deeplearning/lib/python3.8/site-packages/IPython/core/interactiveshell.py", line 3437, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-85-8fe8ab09b722>", line 7, in <module>
    m.f.misstyped_called_once() # raises
  File "/Users/ant/opt/miniconda3/envs/deeplearning/lib/python3.8/unittest/mock.py", line 637, in __getattr__
    raise AttributeError("Mock object has no attribute %r" % name)
AttributeError: Mock object has no attribute 'misstyped_called_once'

It turns out there's a whole section devoted to this topic in the docs: https://docs.python.org/3/library/unittest.mock.html#autospeccing

Autospeccing is based on the existing spec feature of mock. It limits the api of mocks to the api of an original object (the spec), but it is recursive (implemented lazily) so that attributes of mocks only have the same api as the attributes of the spec.

EDIT

Looks there's a school of thought that avoids using the assert_called_xxx in favour of explicit

assert mock_restart.call_count == 1
assert mock_restart.call_args == mock.call(“some argument”)

and another school that proposes a methodological solution -- if you do TDD, then your test must fail before you put in any implementation and this guards against the false positives.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM