Explain how @InjectMocks resolves which mock goes where, and what happens when multiple mocks share the same type.
answer
- Order: constructor → setter → field
- Match by type, tie-break by name
- Same-type mocks: name must equal target field/param
- Unmatched dependency = null, no error
- No mixing strategies to finish one object
basics
~20 sMockito tries constructor injection, then setters, then fields. It matches mocks by type; if several mocks have the same type it falls back to matching the field name. Anything it can't match is left null.
solid answer
~50 s@InjectMocks resolves dependencies in three strategies, in order: constructor injection (picking the biggest constructor it can satisfy), then property/setter injection, then direct field injection by reflection. Within a strategy it matches each dependency primarily by type. When two mocks share the same type, type alone is ambiguous, so Mockito disambiguates by name — the mock field name must equal the target field/parameter name. If names don't line up, Mockito may inject the wrong mock or none, with no error. Crucially, an unsatisfiable dependency is left null rather than failing the test, so you get an NPE later inside the SUT. Mockito also won't mix strategies to fully wire one object: if a usable constructor exists, it uses constructor injection and won't then field-inject the rest. These ambiguities are the main argument many teams make for replacing @InjectMocks with explicit `new` construction passing named mocks.
go deeper
Knows mocks are injected by type and that an unmatched one stays null causing an NPE.
Can state the constructor→setter→field order and that same-type mocks are disambiguated by name.
Explains the full resolution algorithm, the no-strategy-mixing behavior, parameter-name requirements, and the silent-null trap, and can debug a misrouted mock.
Treats @InjectMocks ambiguity as a design signal, mandates constructor injection + explicit test wiring as policy, and reasons about how production DI style affects test clarity at scale.
## The three injection strategies, in order When Mockito processes `@InjectMocks`, it tries to populate the SUT's dependencies using these strategies **in this sequence**, stopping at the first that can construct the object: 1. **Constructor injection.** Mockito looks for the constructor with the **most parameters** and tries to supply a mock for each. It picks the biggest constructor it can fully (or best) satisfy. This works even with `final` fields, since values are passed at construction time. This is the modern, preferred path. 2. **Property (setter) injection.** For dependencies still unset, Mockito calls JavaBean-style setters whose parameter matches an available mock. 3. **Field injection.** As a last resort, Mockito writes directly into fields via reflection, including `private` ones. Importantly, Mockito does **not** combine constructor + field injection to finish wiring a single object. If it chooses constructor injection and the constructor leaves some collaborator out, those are not then field-injected. This causes confusing partially-wired SUTs. ## Matching: type first, then name Within a strategy, Mockito matches each target slot to a mock: - **By type.** If exactly one mock is assignment-compatible with the slot, it is used. - **By name (tie-breaker).** If **multiple mocks share a type**, type is ambiguous. Mockito then compares the **field/parameter name** of the target against the **field name** of the mock. Whichever name matches wins. ### Worked ambiguity ```java class NotificationService { private final MessageSender primary; private final MessageSender fallback; NotificationService(MessageSender primary, MessageSender fallback) { ... } } @ExtendWith(MockitoExtension.class) class NotificationServiceTest { @Mock MessageSender primary; // name matches the 'primary' param @Mock MessageSender fallback; // name matches the 'fallback' param @InjectMocks NotificationService service; } ``` Both mocks are `MessageSender`, so type can't decide. Because the **field names** (`primary`, `fallback`) match the constructor parameter names, Mockito routes each to the right slot. **Rename one mock** and the matching breaks — Mockito may inject the wrong sender, and your test silently exercises the wrong wiring. > Note: parameter-name matching requires the names to actually be present in the bytecode (compiled with `-parameters` or via field names); otherwise Mockito cannot use names to disambiguate and the result is unspecified. ## Silent failure: the null trap The single biggest gotcha: if Mockito **cannot** match a dependency at all, it leaves it `null` and **does not fail**. The test compiles and starts, then throws `NullPointerException` deep inside the SUT when that collaborator is used. Because the error surfaces far from the cause, it is hard to diagnose. There is no "missing dependency" exception. ## Why teams move away from @InjectMocks Because of name-coupling, silent nulls, and the no-mixing rule, many codebases prefer **explicit construction**: ```java @Mock MessageSender primary; @Mock MessageSender fallback; NotificationService service; @BeforeEach void setUp() { service = new NotificationService(primary, fallback); // explicit, order-checked } ``` This is compiler-checked, fails loudly if you forget a dependency, and makes the wiring obvious — at the cost of a little boilerplate. It also pushes you toward **constructor injection in production code**, widely considered better design (immutable dependencies, no reflection needed). ## Summary checklist - Order: constructor → setter → field. - Match: type, then name. - Same-type mocks must be named after their target slots. - Unmatched ⇒ null, no error. - Mockito won't mix strategies to finish one object.
- You have two mocks of the same interface and the wrong one seems to be injected. What's the likely cause and fix?The mock field names don't match the target field/parameter names, so type-only matching picks ambiguously. Rename the @Mock fields to match the targets, or construct the SUT explicitly with new.
- Why does a forgotten dependency surface as an NPE rather than a clear Mockito error?@InjectMocks leaves any unmatched dependency null instead of failing, so the failure only appears when the SUT later dereferences that null collaborator.
saying these in an interview costs you the question
- Saying Mockito throws an error when a dependency can't be injected
- Assuming same-type mocks are routed automatically regardless of name
- Believing Mockito combines constructor + field injection to fully wire one SUT
- Thinking field injection happens before constructor injection