Trying to wrap my head around the difference between Spec and Autospec. They seem to be about the same. Specifically, if you look at mock.patch decorator.
Can someone explain when to use which?
https://docs.python.org/3/library/unittest.mock.html
spec: This can be either a list of strings or an existing object (a class or instance) that acts as the specification for the mock object. If you pass in an object then a list of strings is formed by calling dir on the object (excluding unsupported magic attributes and methods).
With Mock you can mock magic methods but you have to define them. MagicMock has "default implementations of most of the magic methods.". If you don't need to test any magic methods, Mock is adequate and doesn't bring a lot of extraneous things into your tests.
Mock is a type, and patch is a context. So you are going to pass or receive Mock instances as parameters, and apply patch contexts to blocks of code. (Lowercase 'mock' is just the name of the package.) Tests and test classes are often decorated with calls to patch.
mock documentation for side_effect : If you pass in an iterable, it is used to retrieve an iterator which must yield a value on every call. This value can either be an exception instance to be raised, or a value to be returned from the call to the mock ( DEFAULT handling is identical to the function case).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With