Yeda AI Tips · #081

Español

Always Mock With Autospec True

Your mocks accept methods that do not exist. A plain Mock (or MagicMock) is infinitely agreeable: call mock.fetch_userz(), mock.send(1, 2, 3, 4, 5), or any misspelled, renamed, or hallucinated method, and it happily returns another mock. The test goes green. In an AI-assisted codebase — where an agent may rename a method, guess a parameter, or invent an API — that agreeableness turns your test suite into a rubber stamp.

Why a plain Mock lies to you

Mock auto-creates attributes on access. That is the feature that makes mocking convenient, and it is also the failure mode: nothing ties the mock to the real object's interface. Concretely, two things go unchecked:

  1. Nonexistent attributes. Rename Client.get_user to Client.fetch_user in production code. A test that patches Client with a plain mock and calls client.get_user() still passes — the mock invents get_user on the spot.
  2. Wrong signatures. Add a required argument to a real function. Tests calling the mocked version with the old arity still pass, because a plain mock accepts any call.

Both are exactly the mistakes AI coding assistants make most often: plausible-but-wrong method names and slightly-off call signatures.

The fix: autospec=True

Pass autospec=True to patch() and the mock is built from the real object's spec — recursively. Per the Python docs: "All attributes of the mock will also have the spec of the corresponding attribute of the object being replaced," and mocked functions "will have their arguments checked and will raise a TypeError if they are called with the wrong signature."

from unittest.mock import patch

# Rubber stamp: passes even if get_user() was renamed
with patch("app.client.Client") as mock_client:
    mock_client.return_value.get_userz()          # green, silently wrong

# Reality check: fails the moment the API drifts
with patch("app.client.Client", autospec=True) as mock_client:
    mock_client.return_value.get_userz()          # AttributeError
    mock_client.return_value.get_user("a", "b")   # TypeError if the real
                                                  # signature is get_user(id)

Accessing an attribute the real object doesn't have raises AttributeError; calling with the wrong arguments raises TypeError — the same way production code would fail. Your tests now catch AI misuse of an API instead of quietly hiding it.

Rules of thumb

SituationUse
patch() a class, function, or module attributepatch(target, autospec=True) — the default habit
Build a spec'd mock by hand (no patching)create_autospec(RealThing)
Also forbid setting attributes that don't existspec_set=True (stricter variant of spec)
Mock should act like an instance, not the classcreate_autospec(RealThing, instance=True)
Legacy plain mocks you can't rewrite yetat minimum patch(target, spec=True)

spec=True checks attribute access; spec_set=True additionally raises AttributeError when a test assigns an attribute the real object lacks — which catches typos in your test setup itself.

Power-user notes

Resources

Building an AI feature? Yeda AI designs, audits, and ships production LLM systems.

Talk to us · Read the blog