Sometimes, code I write initially is very much part of the discovery process. Initial attempts will be scrapped and refactored aggressively until I begin to settle on the overall structure and design of the application. At this point I will begin retroactively writing tests for existing code and switching to a more test-driven design approach for new code.
Unfortunately, I've been bitten a few times when using python's mock library by misunderstanding of the pitfalls around autospec defaulting to false, as described in this blog post.
Mock objects are designed to track all interactions with them, including calls to methods and class attributes that do not exist in the object being mocked. That means making method calls that do not exist in the original object will not raise any kind of error.
Therefore, following a very strict TDD approach is required to ensure that none
of the tests are written so that they always pass. In my case, I was doing
assert_called_once -- which is not part of the Mock API and so that test will
always pass.
Additionally, if code is refactored in such a way that a mocked object's API changes, but the tests are not refactored with it, then they will continue to pass although their new API is not being tested.
In a mock object, Auto-speccing is disabled by default. If it is enabled, a the instantiated Mock copies the API of the mocked object into its own spec recursively. Calls to non-existent class attributes will result in exceptions.
If we want to use auto-speccing by default without adding the autospec
parameter to every last call to mock.patch(), we can define our own patch
object:
import mock
def my_patch(*args, autospec=True, **kwargs):
return mock.patch(*args, autospec=autospec, **kwargs)Alternatively:
import mock
import functools
my_patch = functools.partial(mock.patch, autospec=True)The mock library also includes the create_autospec() function.
mockprovides a MagicMock and a NonCallableMagicMock object. When patching an object, does using autospecing or not affect whether the mocked object is callable?