1.Mock, MagicMock, patch, AsyncMock, and monkeypatching
`Mock` is an object that accepts any attribute access and any call, records what happened, and returns another `Mock`. `MagicMock` is the same with the dunder methods configured, so it supports `len()`, iteration, `in`, and context managers — which is why it is what `patch` gives you by default. `AsyncMock` returns a coroutine when called, so it stands in for anything you `await`. `patch` temporarily replaces an attribute for the duration of a test and puts the original back afterwards, and pytest's `monkeypatch` fixture does the same for attributes, dictionary entries and environment variables. The single rule that decides whether any of this works: **patch where the name is used, not where it is defined**.
Key features
- `Mock` accepts any attribute and any call; modern Python raises for names starting with `assert`, but `called_once_with` (no prefix) silently passes — `autospec=True` is what catches it
- `MagicMock` adds configured dunders (`__len__`, `__iter__`, `__enter__`, …), which is why `patch` returns one by default
- `AsyncMock` returns a coroutine when called; patching an async function with a plain `Mock` gives a `TypeError` about awaiting a `Mock`
- Patch where the name is **used**, not where it is defined: `from x import y` copies the reference into the importing module
- `patch` works as a decorator, a context manager, or `start()`/`stop()`; all three restore the original afterwards
- pytest's `monkeypatch` covers `setattr`, `setitem`, `setenv` and `delattr` with automatic teardown — better than `patch` for environment and dict entries
Which double, and when
- Whole: @patch("orders.services.charge_card", autospec=True, return_value="ch_1")
- @patch — temporary, and self-undoing: Replaces the attribute for the duration of the test and restores it afterwards, whether the test passes, fails, or raises.
- "orders.services — the module where the name is LOOKED UP: Not where the function is defined. `from billing import charge_card` copies the reference into orders.services, so that is the namespace to patch.
- .charge_card" — the attribute being replaced: A string, resolved at call time — which is why a typo here silently patches nothing unless autospec catches it.
- autospec=True — the guardrail: Builds the double from the real signature, so a wrong argument count or a nonexistent method raises instead of quietly returning another Mock.
- return_value="ch_1" — what the call answers: Without it the call returns a Mock, which is truthy and often passes an assertion by accident. Use side_effect instead to raise or to vary per call.
Command
with patch("orders.views.charge_card", autospec=True) as charge:
charge.side_effect = PaymentDeclined("insufficient funds")
...`Mock` says yes to everything, which is why a mistyped assertion silently passes — use `autospec=True` as the default so a wrong signature or a fabricated method raises. `MagicMock` adds dunders, `AsyncMock` returns coroutines and is counted with `await_count`. Patch where the name is **used**, because `from x import y` copies the reference into the importing module. And prefer `monkeypatch` for environment variables and dictionary entries, where its teardown is cleaner than `patch.dict`.