skip to content

Mockito's @InjectMocks can wire a dependency in more than one way. Which injection strategies does it try, in what order, and how does it choose a constructor when the class under test declares several?

level: middleimportance: must knowfreq 62%

answer

  1. Constructor → setter → field, first success wins
  2. Biggest constructor = most parameters
  3. Unmatched constructor arg → null, silently
  4. Setter/field skipped once constructor succeeded
  5. Field injection skips static and final

basics

~20 s

Mockito tries constructor injection first, then property setter injection, then direct field injection, and stops at the first strategy that works — it does not combine them. For constructors it picks the one with the most parameters and resolves each argument by type, passing null for anything it cannot match.

solid answer

~50 s

The order is **constructor → property setter → field**, and it is *first one wins*, not cumulative. **Constructor injection** runs when the `@InjectMocks` field is not already initialized. Mockito selects the **biggest constructor** — the one with the most parameters — and resolves each parameter by type from the pool of `@Mock`/`@Spy` fields. A parameter with no matching mock is passed as `null`. If the biggest constructor is the no-arg one, this strategy is skipped. If the object was instead already created (either by you, `@InjectMocks Service s = new Service();`, or through the no-arg path), Mockito falls back to **setter injection**: for each field, it looks for a matching setter and calls it. Failing that it writes the field **directly by reflection**, skipping `static` and `final` fields. The consequence people trip over: once the biggest constructor succeeds, no setter or field injection happens afterwards. A dependency that is only settable through a setter, on a class that also has a wide constructor, never gets injected.

code

java · 20 lines
java
class ReportService {
    private final Repo repo;
    private final Clock clock;
    private Auditor auditor;              // setter-only dependency

    ReportService(Repo repo, Clock clock) { // biggest constructor -> used
        this.repo = repo;
        this.clock = clock;
    }

    void setAuditor(Auditor auditor) { this.auditor = auditor; }
}

@ExtendWith(MockitoExtension.class)
class ReportServiceTest {
    @Mock Repo repo;
    @Mock Clock clock;
    @Mock Auditor auditor;                 // matched by type, but NEVER injected
    @InjectMocks ReportService service;    // auditor stays null -> NPE at runtime
}

go deeper

for a junior

Recall the order constructor → setter → field and that the field under test is built automatically from the @Mock fields.

for a middle

Explain first-success-wins, biggest-constructor selection, type-then-name matching, and the null-instead-of-error behaviour.

for a senior

Reason from the class's shape to which strategy will actually run, and predict the null-field failures that follow a constructor change.

for a principal

Weigh the convenience against silent wiring drift across a large suite, and set a team rule — e.g. single all-args constructor, no same-type dependencies, explicit construction where wiring is part of the contract.

## The chain Mockito's injector is a chain of strategies, each of which either succeeds and terminates the chain or declines and delegates to the next: 1. **Constructor injection** 2. **Property (setter) injection** 3. **Field injection** The crucial word is *chain*. These are alternatives, not phases. Mockito does not construct via the biggest constructor and then also fill in the remaining fields. ## Constructor injection in detail This strategy applies only when the `@InjectMocks` field is still `null` — i.e. you wrote `@InjectMocks OrderService service;` with no initializer. Mockito then inspects the declared constructors and picks the **biggest** one, meaning the greatest number of parameters. Visibility does not exclude a constructor; a package-private or private wide constructor can still be chosen, which sometimes surprises people who added one "just for tests". Each parameter is then resolved against the mock pool **by type**. Assignability is respected, so a `@Mock` declared as a concrete implementation can satisfy an interface parameter. Any parameter with no candidate is filled with `null` — quietly. Two parameters of the same type are the genuinely dangerous case: type alone cannot separate them, and you may get the mocks swapped. When you have same-type dependencies, construct the object explicitly instead of trusting the heuristic. If the chosen constructor throws an exception while Mockito calls it, injection fails and Mockito reports it; but if the constructor merely stores nulls, everything looks fine until the test dereferences one. If the biggest constructor turns out to be the no-arg constructor, the constructor strategy declines, Mockito instantiates the object with that no-arg constructor, and the chain continues to property injection. ## Property setter injection Here Mockito walks the fields of the class under test — including inherited ones, superclass first — and for each looks for a conventional setter (`setFoo` for field `foo`) whose parameter type matches an available mock. If it finds one, it calls it. Using the setter rather than writing the field matters when the setter does something beyond assignment. Candidate selection is again type-first: filter mocks by assignable type; if more than one survives, compare the **mock field's name** to the target property name. Exact name match wins. If the ambiguity cannot be resolved, Mockito may inject nothing for that property. ## Field injection When there is no usable setter, Mockito writes straight into the field with reflection, calling `setAccessible(true)` so `private` is no obstacle. Two categories are excluded: `static` fields and `final` fields. That exclusion is a frequent source of "why is my field still null" — a `private final Clock clock;` initialized in a constructor Mockito did not use will never be populated by field injection. ## Ordering side effects Because the chain stops at the first success, the shape of your class determines which mocks arrive: - Wide constructor present → everything comes through it; setter-only or field-only dependencies stay null. - No-arg constructor only → all dependencies arrive through setters/fields; `final` fields stay null. - `@InjectMocks` field pre-initialized by you → constructor injection is skipped entirely and only setter/field injection runs on your instance. That last case is a legitimate technique when the class needs constructor arguments Mockito cannot supply (a `String` URL, an `int` timeout): build it yourself with the literals and let Mockito fill in the mockable collaborators. ## Nothing is reported The documented contract is explicit that Mockito will **not** report a failure to inject. There is no "could not satisfy dependency" exception. The failure surfaces later as a `NullPointerException` inside production code, with a stack trace pointing at your class, not at the test wiring. When you add a parameter to a constructor and the test compiles unchanged, this is what bites. ## Practical rules - Prefer classes with a single constructor taking all dependencies; then the biggest-constructor rule is unambiguous. - Avoid two dependencies of the same type, or name the mock fields to match the target fields exactly. - Do not rely on setter injection on a class that also has a wide constructor — it will not run. - If wiring matters to the test's meaning, drop the annotation and call the constructor by hand: one line, and it breaks at compile time when the constructor changes.

  • Your class has a wide constructor and you add a new dependency exposed only through a setter. Why does the mock never arrive?
    Because injection stops at the first successful strategy. The biggest constructor succeeds, so property setter injection is never attempted and the new field keeps its default null. The fixes are to add the dependency to the constructor, or to pre-initialize the @InjectMocks field so constructor injection is skipped and setter injection runs.
  • Two constructor parameters have the same type. What does Mockito do?
    Constructor arguments are resolved by type, so two same-type parameters cannot be told apart reliably and the mocks may end up in the wrong slots — with no error. Field and setter injection can fall back to name matching, but constructor injection is the weakest case. The dependable answer is to construct the object explicitly in the test.
  • Why does a private final field sometimes remain null after injection?
    Field injection deliberately skips static and final fields. If the object was created through a no-arg constructor and the dependency lives in a final field, there is no route left to populate it. Either make the dependency a constructor parameter, or drop final on that field, or wire the object manually.

saying these in an interview costs you the question

  • Believing Mockito runs all three strategies and merges the results
  • Thinking the smallest or the public constructor is chosen rather than the one with the most parameters
  • Expecting an exception when a constructor argument cannot be resolved
  • Assuming final or static fields can be filled by field injection
  • Assuming setter injection still runs after a successful constructor injection

context