Python Mock Autospec vs Spec
spec
applies only to the mock instance where it is specified. In particular, if the mocked class a
has a method, e.g. method()
, then calling that method in the instanciated mock of a
will automatically generate and return another mock that is not restricted to any spec. This is where autospec
comes in handy, as it recursively defines specs on whatever is called (within the restrictions of the specs defined up to that point).
From the Mock Autospeccing Helper documentation:
If you use a class or instance as the spec for a mock then you can only access attributes on the mock that exist on the real class:
>>> import urllib2
>>> mock = Mock(spec=urllib2.Request)
>>> mock.assret_called_with
Traceback (most recent call last):
...
AttributeError: Mock object has no attribute 'assret_called_with'
The spec only applies to the mock itself, so we still have the same issue with any methods on the mock:
>>> mock.has_data()
<mock.Mock object at 0x...>
>>> mock.has_data.assret_called_with()
Auto-speccing solves this problem.
spec
is used as a template for your Mock object. In the words of the documentation:
If you use the spec or spec_set arguments then only magic methods that exist in the spec will be created.
This means that you cannot call methods on the mock object that do not exist on the object you are mocking. The documentation explains this like this:
Note If you use the spec keyword argument to create a mock then attempting to set a magic method that isn’t in the spec will raise an AttributeError.
autospec
is basically a shorthand in patch
for passing in the object your patching to the spec
of the MagicMock
being created. Documentation:
If you set autospec=True then the mock with be created with a spec from the object being replaced.