skip to content

How do you configure a unittest.mock.Mock's nested attributes in one call?

level: middleimportance: should knowfreq 35%

answer

  1. Compressing several setup lines into one
  2. Keyword names carrying dots
  3. Dictionary unpacking is mandatory here
  4. Shallow keys applied before deeper ones
  5. One keyword the constructor steals

basics

~10 s

Pass dotted keyword arguments: Mock({'evaluate.return_value': True}) at construction, or mock.configure_mock({'close.side_effect': OSError}) afterwards. The constructor forwards its extra keyword arguments to configure_mock, so both forms do the same work.

solid answer

~40 s

`Mock(**kwargs)` hands its surplus keyword arguments straight to `configure_mock`, and both understand *dotted* keys: `Mock(**{"evaluate.return_value": True, "close.side_effect": OSError})` walks the attribute chain, auto-creating each child mock, and sets the final attribute. That collapses several setup lines into one statement, which is why it is the idiomatic way to configure a double at construction time. Keys are applied fewest-dots-first, so a shallow assignment can never clobber a deeper one made in the same call. The trap is `name`: it is a genuine parameter of the `Mock` constructor used for the mock's repr, so `Mock(name="flags-client")` names the mock rather than setting an attribute — reading `.name` still gives an auto-created child. Use `configure_mock(name=...)`, or plain assignment, when you need an attribute called `name`.

code

python · 11 lines
python
from unittest.mock import Mock

client = Mock(**{
    "evaluate.return_value": {"enabled": True},
    "close.side_effect": OSError("socket already closed"),
})
print(client.evaluate("beta-banner"))
try:
    client.close()
except OSError as exc:
    print("raised:", exc)

go deeper

for a junior

Know that a mock can be configured at construction with keyword arguments, and that a dotted key like 'evaluate.return_value' has to be passed through dictionary unpacking.

for a middle

Explain that the constructor forwards surplus kwargs to configure_mock, that dotted keys walk and auto-create child mocks, and why the name keyword configures the mock's repr instead of an attribute.

for a senior

Show that you use the compressed form to keep arrange blocks readable and table-driven, and that you recognise a deep dotted key as a test coupling itself to a dependency's internals.

for a principal

Own the convention. Decide how deep the team's doubles may be configured before a shared in-memory fake replaces them, since chained configuration is the mechanism by which one dependency refactor breaks a hundred unrelated tests.

Configuring a test double one line at a time gets verbose quickly: a client with two methods, one of which returns an object with its own attributes, is four or five statements of setup before the test does anything. `configure_mock` and the `Mock` constructor's keyword arguments exist to compress that. ### Dotted keys walk the attribute chain Both accept keyword arguments whose *names* may contain dots: ```python client = Mock(**{ "evaluate.return_value": {"enabled": True}, "close.side_effect": OSError("socket already closed"), }) ``` For each key, the implementation splits on `.`, pops the final segment, walks the remaining segments with `getattr` — auto-creating child mocks as it goes — and calls `setattr` for the last one. So `"evaluate.return_value"` resolves the child `client.evaluate` and sets `return_value` on it. Depth is unlimited: `"session.get.return_value.status"` is a perfectly valid key. Note that the `**{...}` unpacking is not decorative — `Mock(evaluate.return_value=1)` is a syntax error, because a keyword argument name must be an identifier. Dictionary unpacking is the only way to smuggle a dotted name in. The constructor is not a separate mechanism: any keyword argument it does not recognise as one of its own parameters is forwarded to `configure_mock`. Anything you can do at construction you can also do later on an existing mock, which matters when a fixture creates the double and individual tests refine it. ### Application order is deliberate `configure_mock` sorts its keys by the number of dots and applies the shallowest first. The reason is subtle but important: setting `"evaluate.return_value"` *replaces* the object that `client.evaluate()` returns, so if the deeper key `"evaluate.return_value.status"` had been applied first, its work would be discarded. Shallow-first means both keys in one call compose correctly. Relying on that is fine; relying on the order of *equally deep* keys is not, since it falls back to alphabetical sorting of the key names. ### The name collision The one real trap is `name`. `Mock` takes `name` as an actual constructor parameter and uses it for the mock's `repr`, which is genuinely useful when a failure message would otherwise show three indistinguishable mocks. So `Mock(name="flags-client")` does not create an attribute; reading `.name` afterwards still returns an auto-created child mock, and an assertion comparing it to a string fails with a confusing message. The workarounds are to configure it after construction — `mock.configure_mock(name="flags-client")`, which goes through plain `setattr` — or simply `mock.name = "flags-client"`. The same shadowing applies to every other real parameter of the constructor: `spec`, `spec_set`, `side_effect`, `return_value`, `wraps` and `parent` are consumed by `Mock` itself, so an object under test whose attribute is genuinely called `wraps` or `spec` cannot have it configured through constructor kwargs either. The rule to remember is that constructor keywords are *shared* between mock configuration and attribute configuration, and mock configuration wins. ### When to reach for it, and when not to The compressed form pays for itself when a double needs three or more settings, or when the double is created inside a helper that receives its configuration as a dict — a table-driven test can then carry a `{"evaluate.return_value": ...}` mapping per case and build the double from it. It also keeps arrange blocks readable: one statement that visibly describes the whole collaborator beats five scattered assignments. It does not change any semantics. A dotted key is exactly equivalent to the assignments it performs, so everything about `return_value` and `side_effect` still applies: the value comes back by identity, an exception assigned to `side_effect` is raised, an iterable is consumed once. The honest caution is the same one that applies to long attribute chains generally. A key like `"session.get.return_value.json.return_value"` encodes four assumptions about a collaborator's internals into a test that is nominally about your own code. When those chains multiply across a suite, a small refactor in the dependency breaks dozens of tests that never meant to depend on it. At that depth a hand-written fake, or a narrower interface between your code and the dependency, is usually the better answer — the compression is a convenience, not a licence to reach deeper. All of this behaves identically across Python 3.10–3.14. ### Mixing constructor parameters with dotted keys Because the constructor's own parameters and the forwarded configuration keys share one keyword namespace, a single call can do both jobs: `Mock(return_value=3, **{"evaluate.side_effect": KeyError})` configures the mock's own result *and* a child's behaviour. Read that call carefully — the bare `return_value` belongs to `client()` while the dotted key belongs to `client.evaluate()`, and confusing the two is the same mistake as setting `return_value` on the parent instead of the called child. When a setup line starts mixing both in a way that needs a second read, splitting it into named statements is worth more than the compression.

  • Why does configure_mock apply its keys fewest-dots-first?
    Because a shallower assignment replaces the object a deeper one was configured on. Setting `"evaluate.return_value"` swaps out what `evaluate()` returns, so if `"evaluate.return_value.status"` had been applied first its work would vanish. Sorting by dot count guarantees parents are set before children, letting both keys appear in a single call.
  • Which other keyword names does the Mock constructor consume before they reach attribute configuration?
    Its own parameters: `spec`, `spec_set`, `side_effect`, `return_value`, `wraps`, `parent` and `name`. Any of those in the constructor call configures the mock itself rather than creating an attribute of that name, so a collaborator with an attribute genuinely called `wraps` or `name` must be configured afterwards with `configure_mock` or plain assignment.
  • When is a long dotted configuration key a smell rather than a convenience?
    When the chain describes the dependency's internals rather than your seam with it. A key like `"session.get.return_value.json.return_value"` bakes four structural assumptions into a test about your own code, so an unrelated refactor in the dependency breaks it. At that depth a small hand-written fake, or a narrower interface, ages far better.

saying these in an interview costs you the question

  • Thinks Mock(name='x') sets a name attribute
  • Writes Mock(evaluate.return_value=1) without dictionary unpacking
  • Believes configure_mock discards earlier configuration
  • Assumes deeper keys are applied before shallower ones
  • Expects Mock(spec=...) to create an attribute called spec

context