How does @MockitoBean decide which bean to replace, and what do the name and enforceOverride attributes control?
answer
- default = match by field type
- multiple candidates → set name/value
- no match → creates NEW bean (create-if-absent)
- enforceOverride=true → existing bean required, fail fast
- @MockitoSpyBean needs a real bean; spy runs real methods
basics
~20 sBy default it matches the bean by the field's type. If several beans share that type you must set name (or value) to pick one. If no bean matches, it normally registers the mock as a new bean; enforceOverride = true instead requires an existing bean and fails otherwise.
solid answer
~50 s@MockitoBean resolves the target bean by-type using the annotated field's declared type. If exactly one bean of that type exists, it is replaced. If multiple candidates exist, resolution is ambiguous and you must disambiguate with @MockitoBean(name = "beanName") (name and value are aliases); by-name matching then targets that specific bean. A subtle default: if no bean matches, @MockitoBean does not fail — it registers the mock as a brand-new bean in the context (a 'create if absent' semantic). That is convenient but can hide a wiring mistake (you think you're mocking an existing collaborator but you silently added a new one). Setting enforceOverride = true makes an existing original mandatory: the framework then fails fast if there is nothing to override. You can also declare @MockitoBean at class level with types = { A.class, B.class } to mock several beans without one field each, and choose the reset strategy per declaration.
code
java · 17 lines@SpringBootTest
class PaymentTest {
// Ambiguity: two PaymentGateway beans exist -> disambiguate by name.
@MockitoBean(name = "stripeGateway")
PaymentGateway stripe;
// Fail fast if nothing matches, instead of silently adding a phantom mock.
@MockitoBean(enforceOverride = true)
FraudCheck fraudCheck;
@Test
void chargesViaStripe() {
when(stripe.charge(any())).thenReturn(ChargeResult.approved());
// ...
}
}go deeper
Know it matches by type and you can set a name.
Know that multiple beans of a type need the name attribute to disambiguate.
Explain the create-if-absent default vs enforceOverride and the phantom-mock risk.
Advise on enforceOverride policy and class-level types usage across a codebase to prevent silent test drift.
## Resolution: by type, then by name `@MockitoBean` uses the Bean Override framework's resolution rules: 1. **By type (default).** The annotated **field's declared type** is the type to replace. If **exactly one** bean of that type exists in the context, it is swapped for the mock. 2. **Ambiguity.** If **more than one** bean of that type exists, by-type resolution is ambiguous and the context fails to load. You resolve it by naming the target: `@MockitoBean(name = "primaryGateway")`. The `name` and `value` attributes are **aliases** for each other. 3. **By name.** When `name` is set, resolution targets the bean with that **exact name**. ## The 'create if absent' default vs enforceOverride A frequently-missed detail: **by default `@MockitoBean` does not require the bean to exist.** If no matching bean is found, it **registers the mock as a new bean** in the context rather than failing. This is handy (you can inject a mock for a type nothing currently provides) but dangerous — a typo in the `name`, or a refactor that renamed the real bean, can leave you **testing against a phantom mock** while the real collaborator is untouched, and the test still 'passes'. - `@MockitoBean(enforceOverride = true)` flips this: an **existing** original bean becomes **required**. If none matches, the context load **fails fast**, catching the mistake. Use it when you specifically intend to *replace* something and want to be told if it isn't there. ## Class-level declaration and multiple types Since 6.2 you can annotate the **test class** (repeatably) and specify `types`: ```java @MockitoBean(types = { PaymentGateway.class, EmailSender.class }) class CheckoutTest { ... } ``` This registers mocks for several types without declaring a field for each — useful when you only need the mock to exist in the context (e.g., to satisfy wiring) and don't need to stub it directly. When you *do* need to stub, use a field so you have a reference. ## Other attributes - `reset` — `MockReset` strategy (default `AFTER`); see the reset-behaviour question. - `extraInterfaces`, `serializable`, `answers` — passthrough to Mockito mock settings (e.g., default `Answer` such as `RETURNS_DEEP_STUBS`). - `contextName` — target a specific context in a hierarchy. ## @MockitoBean vs @MockitoSpyBean `@MockitoSpyBean` wraps the **real** bean in a spy: real methods execute unless stubbed. It **requires an existing bean** to spy on (you cannot spy something that isn't there), which contrasts with `@MockitoBean`'s create-if-absent default. ## Practical guidance - Prefer **by-type** for clarity; reach for `name` only when there are genuinely multiple beans. - Turn on `enforceOverride = true` in codebases that refactor bean names often, to avoid silent phantom-mock bugs. - Use class-level `types` for 'must exist in context' mocks you won't stub.
- You typo the name in @MockitoBean(name = "gatway"). What happens by default, and how do you make it fail?By default the framework finds no matching bean and, instead of failing, registers the mock as a new bean — so the real gateway is never replaced and the test may pass misleadingly. Setting enforceOverride = true makes an existing bean mandatory, so the context load fails fast on the typo.
- How does @MockitoSpyBean differ in its bean-existence requirement?A spy wraps the real bean, so an existing bean is required — there is nothing to create-if-absent. Real methods run unless you stub them (use doReturn().when() to avoid calling the real method during stubbing).
saying these in an interview costs you the question
- Assuming @MockitoBean always fails when the target bean is missing (it creates one unless enforceOverride=true).
- Not knowing that multiple beans of the same type require the name attribute.
- Thinking name and value are different attributes (they are aliases).