Catch an outdated call signature with create_autospec
Also published in our primary archive.
Catch an outdated call signature with create_autospec
To catch an outdated call signature, create an autospec from the real callable. A plain Mock accepts arbitrary keyword arguments, so it can make a test pass even when production would reject the call.
The concrete interface here is request(user, retries). The deliberately stale caller supplies retrise, a misspelling. The loose double returns accepted and records that misspelled keyword; this only proves that the flexible double received it. Calling the real function with that input raises TypeError, which establishes the production boundary for this fixture.
create_autospec(request, return_value="stub") copies the callable's signature for the mock. The autospecced mock raises TypeError for the same bad keyword before it can return its configured value. A correct user/retries invocation does return stub and is asserted exactly once. Thus the experiment separates interface validation from the result the test wants to simulate.
Autospeccing is not a promise that the function's implementation, network behavior, or returned data is real; it constrains available attributes and callable signatures. It has been available with unittest.mock since Python 3.3. The official create_autospec() documentation describes its signature-copying behavior.
AI assistance disclosure: this article and executable example were drafted with AI assistance.
from unittest.mock import Mock, create_autospec
def request(user, retries):
return f"real:{user}:{retries}"
loose = Mock(return_value="accepted")
assert loose(user="Batu", retrise=2) == "accepted"
loose.assert_called_once_with(user="Batu", retrise=2)
try:
request(user="Batu", retrise=2)
except TypeError:
real_rejected = True
else:
real_rejected = False
assert real_rejected
checked = create_autospec(request, return_value="stub")
try:
checked(user="Batu", retrise=2)
except TypeError:
autospec_rejected = True
else:
autospec_rejected = False
assert autospec_rejected
assert checked(user="Batu", retries=2) == "stub"
checked.assert_called_once_with(user="Batu", retries=2)
print("loose typo: accepted")
print("real and autospec typo: TypeError")
print("autospec valid call: stub")
loose typo: accepted
real and autospec typo: TypeError
autospec valid call: stub