skip to content

What does Mock.assert_called_once_with check that Mock.assert_called_with does not?

level: juniorimportance: must knowfreq 68%

answer

  1. Same argument check, different tolerance
  2. One of them counts the calls
  3. Last call versus exactly one call
  4. call_count == 1 checked before arguments
  5. assert_any_call scans call_args_list

basics

~10 s

assert_called_with only inspects the mock's most recent call. assert_called_once_with additionally requires that the mock was called exactly once, so a second, accidental call fails the test.

solid answer

~40 s

Both compare one recorded call's positional and keyword arguments against what you pass, using `==` per argument. The difference is how many calls they tolerate. `assert_called_with(...)` looks only at `mock.call_args`, the **last** call, so a mock called five times still passes as long as the fifth call matched. `assert_called_once_with(...)` first checks `mock.call_count == 1`, then compares that call, so a duplicate call is caught. When you only care that a particular call happened somewhere among many, `assert_any_call(...)` searches `mock.call_args_list`; `assert_not_called()` asserts `call_count == 0`. All of them raise `AssertionError` on failure rather than returning a boolean. A frequent slip is asserting on the wrong object: `sink.emit(x)` records on the child mock `sink.emit`, so the assertion belongs on `sink.emit`, not on `sink`.

code

python · 14 lines
python
from unittest.mock import Mock

sink = Mock()
sink.emit("KJ118", gate="A12")
sink.emit("KJ204", gate="B03")

sink.emit.assert_any_call("KJ118", gate="A12")     # ok: matches some call
sink.emit.assert_called_with("KJ204", gate="B03")  # ok: matches the LAST call
print(sink.emit.call_count, sink.emit.call_args_list)

try:
    sink.emit.assert_called_once_with("KJ204", gate="B03")
except AssertionError as exc:
    print("failed:", exc)

go deeper

for a junior

Be ready to say the plain difference out loud: one checks the last call, the other checks the last call and that it was the only one. Know that these helpers raise AssertionError rather than returning True or False.

for a middle

Explain the mechanics: arguments are compared as a call object with ==, positional and keyword arguments are compared as written, and assert_called_once_with checks call_count first. Know call_args, call_args_list and call_count as the underlying record.

for a senior

Show judgment about which assertion belongs in which test. Demonstrate that a duplicate call is a real production defect class, and that comparing call_args_list is how you assert a complete interaction rather than a partial one.

for a principal

Own the convention: which assertion strength your test suite defaults to, and when interaction assertions are worth their coupling to implementation at all versus asserting on the observable outcome instead.

`unittest.mock` records every call a mock receives, and then hands you a family of assertion helpers to interrogate that record. The two that get confused are `assert_called_with` and `assert_called_once_with`, and the difference between them is not about the arguments — both compare arguments identically — but about how many calls the mock is allowed to have received. ## What "matching" means Each call is stored as a `call` object: a positional-argument tuple plus a keyword-argument dict. `mock.call_args` is the most recent one, `mock.call_args_list` is all of them in order, `mock.call_count` is how many there were, and `mock.called` is the boolean. Since 3.8 you can read a recorded call's parts by name with `mock.call_args.args` and `mock.call_args.kwargs`. When you write `mock.assert_called_with(7, gate="A12")`, mock builds the same kind of `call` object out of your arguments and compares it to `mock.call_args` with `==`. That comparison descends into each argument and uses that argument's own `__eq__`, so a list compares by contents and a custom object compares however its class says it should. Positional and keyword arguments are compared *as written*: a bare `Mock` knows nothing about the real function's signature, so a call made as `f(1)` does not match an assertion written as `f(x=1)`. (Binding assertions to a real signature is what constraining a mock to the real object is for; that is a separate mechanism.) ## The count is the whole difference `assert_called_with` reads only `call_args` — the final call. A mock called five times passes if and only if the fifth call matched; the first four are invisible to it. That is exactly right when the mock is a logger or a repeatedly-polled collaborator and you only care about the latest interaction, and exactly wrong when a repeat call would be a defect. `assert_called_once_with` checks `call_count == 1` first. If the count is anything else it raises `AssertionError` with a message naming the count and listing the recorded calls, and it never even looks at the arguments. So it is a strictly stronger assertion, and it is the one you want whenever a second call is itself a bug: a duplicate publish, a retried write, a second outbound request, an idempotent operation performed twice. ## The rest of the family * `assert_called()` — at least one call, arguments not inspected. * `assert_called_once()` — exactly one call, arguments not inspected. * `assert_any_call(*args, **kwargs)` — scans `call_args_list` and passes if *any* recorded call matched, whatever came before or after it. * `assert_not_called()` — `call_count` must be zero. All of these raise `AssertionError` when they fail; none returns a boolean. That matters, because `assert mock.assert_called_once_with(3)` is nonsense — the helper returns `None`, so if it somehow passed, the surrounding `assert` would then fail on `None`. Call the helper as a statement. For anything the helpers do not express, assert on the record directly: `mock.call_count == 2`, `mock.call_args_list == [call(1), call(2)]`, or pick a single call out of `mock.call_args_list[0]`. Comparing `call_args_list` for equality is the way to say "these calls and nothing else", which no `assert_*_with` helper says. ## The child-mock trap A `Mock` auto-creates attributes on access, and each auto-created child is itself a mock with its own call record. So `sink.emit("KJ118")` does not call `sink` — it calls `sink.emit`. `sink.call_count` stays zero and `sink.assert_called_once_with("KJ118")` fails with "Expected to be called once. Called 0 times." The assertion has to name the same attribute the production code called. The parent still sees the interaction in `sink.mock_calls`, but recorded under the child's name. ## Reuse across assertions `mock.reset_mock()` clears `call_args`, `call_args_list`, `mock_calls` and `call_count` so a second phase of a test starts from a clean record. It does not clear a configured return value unless you ask it to, which is why resetting mid-test is usually less readable than building a fresh mock per test. ## Choosing between them in practice Reach for `assert_called_once_with` by default: it is the assertion that fails loudly when the code under test starts doing the right thing twice, and duplicate-call regressions are the kind of bug a mock is uniquely placed to catch. Fall back to `assert_called_with` when repeated calls are expected and only the latest matters, and to `assert_any_call` when the call you care about is one of several and the order is not part of the contract.

  • How does Mock.assert_any_call differ from Mock.assert_called_with?
    `assert_called_with` inspects only `mock.call_args`, the most recent call, so an earlier matching call does not save it. `assert_any_call` scans the whole of `mock.call_args_list` and passes if any recorded call matched, ignoring everything before and after. Use it when the interaction you care about is one of several and its position in the sequence is not part of the contract.
  • A test calls sink.emit(3) but asserts sink.assert_called_once_with(3) and fails. Why?
    `sink.emit(3)` calls the auto-created child mock `sink.emit`, not `sink` itself, so `sink.call_count` is still zero and the assertion reports zero calls. The assertion has to be written on the same attribute the code called: `sink.emit.assert_called_once_with(3)`. The parent does record the interaction, but under the child's name, in `sink.mock_calls`.
  • How do you assert that a mock received exactly two calls and no others?
    The `assert_*_with` helpers cannot express "and nothing else". Compare the record itself: `assert mock.call_args_list == [call(1), call(2)]`, using `unittest.mock.call` to build the expected entries. That checks the count, the order and the arguments in one comparison. For a parent mock whose children were called, compare `mock.mock_calls` instead, whose entries carry the attribute name.

saying these in an interview costs you the question

  • Thinks assert_called_with also checks the mock was called only once
  • Believes assert_called_once_with compares only positional arguments
  • Asserts on the parent mock instead of the child attribute that was called
  • Uses assert_called_with when any one of several calls should match
  • Treats a failing assert_* as returning False rather than raising AssertionError
  • Reads mock.called as proof that the arguments were correct

context