When would you avoid @InjectMocks in favour of constructing the system under test explicitly, and what does that say about your production code?
answer
- Explicit new = compiler-checked, fails loudly, self-documenting
- @InjectMocks = reflection, silent nulls, name coupling
- Hard-to-wire test ⇒ field injection or too many deps in prod
- Long constructor = SRP smell, refactor not suppress
- Constructor injection needs no framework to test
basics
~20 sAvoid @InjectMocks when wiring is ambiguous or hidden — instead just call new Service(mock1, mock2). If you can't construct it cleanly, your production code probably relies on field injection or has too many dependencies, which is a design smell.
solid answer
~50 s@InjectMocks is convenient but injects by reflection, matches by type-then-name, and silently leaves unmatched dependencies null, so misconfigured tests fail far from the cause. I prefer explicit construction — `new Service(repo, encoder)` — because it is compiler-checked, fails loudly on a missing dependency, makes wiring obvious, and survives refactors. The deeper point is that needing @InjectMocks magic often reveals that production code uses field/setter injection rather than constructor injection. Constructor injection makes dependencies explicit, final, and non-optional, lets the compiler enforce completeness, and makes the class trivially testable with plain `new`. If a class has so many constructor args that explicit wiring is painful, that is a signal the class has too many responsibilities and should be split. So @InjectMocks is a useful default for simple cases, but I treat reaching for it on complex classes as a prompt to review the design rather than paper over it.
go deeper
Can use @InjectMocks and knows explicit new is an alternative.
Articulates that explicit construction is compiler-checked and fails loudly while @InjectMocks uses reflection and silent nulls.
Argues for constructor injection in production so tests need no reflection, and chooses per-case between @InjectMocks and explicit wiring.
Sets team policy linking production DI style to test clarity, reads test friction as design feedback (SRP, dependency count), and decides when @InjectMocks is acceptable vs a smell to refactor.
## The convenience vs the cost `@InjectMocks` removes a line of setup: instead of writing `new Service(a, b, c)` you let Mockito reflectively wire the mocks. For a small, well-named class this is harmless. The cost shows up as classes grow and as wiring gets ambiguous. ### What @InjectMocks costs you 1. **Reflection, not compilation.** Wiring happens at runtime by reflection. The compiler can't verify it. Rename a field, add a dependency, reorder constructor params — the test may keep compiling but wire incorrectly. 2. **Silent nulls.** An unmatched dependency is left `null` with no error; you get an NPE deep inside the SUT, disconnected from the cause. 3. **Name coupling.** Same-type mocks are disambiguated by field name, coupling test field names to production member names. 4. **No strategy mixing.** If a constructor is used, leftover dependencies are not field-injected, producing partially-wired objects. 5. **Hides design problems.** Because it can field-inject `private` members, it lets you test classes that have **no usable constructor** — which quietly encourages field injection in production. ### Why explicit construction is usually better ```java @Mock UserRepository repo; @Mock PasswordEncoder encoder; UserService service; @BeforeEach void setUp() { service = new UserService(repo, encoder); } ``` - **Compiler-checked:** forget a dependency and it won't compile. - **Fails loudly:** a wrong or missing arg is obvious at the construction line, not 40 lines into the SUT. - **Self-documenting:** the wiring is right there. - **Refactor-safe:** changing the constructor forces the test to update. The small price is one explicit line per test class (or a helper). ## The production-code reflection The ability to even *use* explicit construction depends on a design choice in production code: - **Constructor injection** (dependencies passed in the constructor, stored in `final` fields) makes the class instantiable with plain `new`, makes dependencies explicit and mandatory, supports immutability, and needs **no framework** to test. This is the style Effective Java, the Spring team, and clean-architecture practice all recommend. - **Field/setter injection** (a DI container writes into `@Autowired` fields after construction, or setters do) leaves no constructor that lists dependencies, so tests must use reflection (`@InjectMocks` field injection) or a container. It also allows objects to exist in a half-constructed, invalid state. So when a class is awkward to test without `@InjectMocks`, that is frequently a **symptom**: it relies on field injection, or it simply has too many collaborators. ## Too many dependencies = a design smell If explicit construction feels painful because the constructor has six or eight parameters, the right response is **not** to hide it behind `@InjectMocks` — it is to question the class's responsibilities. A constructor that long usually violates the Single Responsibility Principle; the class should be decomposed, or related collaborators grouped behind a smaller abstraction. The friction in the test is doing its job: it is **design feedback**. `@InjectMocks` mutes that feedback. ## A pragmatic policy - Default to **constructor injection** in production code. - In tests, prefer **explicit `new`** wiring; reserve `@InjectMocks` for genuinely simple, unambiguous cases or legacy code you can't change. - Treat "I need @InjectMocks field injection because there's no constructor" and "the constructor is too long to wire by hand" as **prompts to refactor**, not problems to suppress. - Keep strict stubbing on so dead test wiring is caught early. ## Nuance: when @InjectMocks is fine None of this makes `@InjectMocks` wrong everywhere. For a class with one or two clearly-named, distinct-typed dependencies and a constructor, `@InjectMocks` is concise and safe. The judgement is about **recognising when its conveniences are masking a real problem** rather than saving keystrokes.
- A teammate says they need @InjectMocks because the class has no constructor that takes its dependencies. What does that tell you?The class uses field/setter injection, leaving it half-constructable. The better fix is to add constructor injection with final fields, which makes it testable with plain new and enforces complete, valid construction.
- Your constructor has seven dependencies and explicit test wiring is tedious. Best response?Treat the tedium as design feedback: the class likely violates SRP. Decompose it or group collaborators behind a smaller abstraction, rather than hiding the count behind @InjectMocks.
saying these in an interview costs you the question
- Treating @InjectMocks as strictly better because it's less code
- Suppressing a painful 8-arg constructor with @InjectMocks instead of splitting the class
- Claiming field injection in production is equivalent to constructor injection for testability
- Not recognizing test friction as design feedback