@InjectMocks Silent Injection Failure
Fast recall
Quick revision
Core answer
@InjectMocks can leave a collaborator null when no declared mock or spy matches it, because Mockito does not report every unsatisfied injection point as an error. The failure often appears later when the test executes that path. However, not every injection problem is silent: Mockito can fail setup if it cannot instantiate the target or its constructor throws. Strict stubbing does not validate injection; it reports unused or mismatched stubs.Interview-ready guide
Interview answer
When @InjectMocks cannot match a declared mock or spy to one dependency, Mockito may leave that collaborator null instead of reporting an unsatisfied injection point. The test then fails later only if execution reaches code that uses the field.
That does not mean every problem is silent. Mockito can fail setup when the target is an interface, abstract class, non-static inner class, or otherwise cannot be instantiated. A constructor that throws can also produce a setup error.
Strict stubbing does not validate the injection graph. It reports unnecessary stubs and certain stubbing mismatches, so an unused stub may be a clue but not proof. Required constructor dependencies make invalid objects harder to create, and explicit test construction—service = new Service(repo, gateway)—makes missing arguments visible to the compiler.
@InjectMocks Silent Injection Failure
Direct Answer
@InjectMocks can leave a collaborator null when no declared mock or spy matches it, because Mockito does not report every unsatisfied injection point as an error. The failure often appears later when the test executes that path. However, not every injection problem is silent: Mockito can fail setup if it cannot instantiate the target or its constructor throws. Strict stubbing does not validate injection; it reports unused or mismatched stubs.
Code Example
class PaymentService {
private final PaymentGateway gateway;
private final AuditLogger auditLogger; // not injected due to typo
public PaymentService(PaymentGateway gateway) {
this.gateway = gateway;
// auditLogger stays null
}
public void processPayment(double amount) {
gateway.charge(amount);
auditLogger.log("Payment processed"); // NPE here at runtime
}
}
@ExtendWith(MockitoExtension.class)
class PaymentServiceTest {
@Mock private PaymentGateway gateway;
@Mock private AuditLogger auditLoger; // typo: auditLoger vs auditLogger
@InjectMocks private PaymentService service;
@Test
void shouldProcessPayment() {
when(gateway.charge(100.0)).thenReturn(true);
// NPE thrown here because auditLogger is null
service.processPayment(100.0); // test fails with confusing NPE
}
}
// FIXED VERSION: Manual construction catches the issue
@BeforeEach
void setUp() {
service = new PaymentService(gateway, auditLogger); // compile error if types wrong
}
Common Mistakes & Pitfalls
- Trusting @InjectMocks to Fail Loudly: Freshers assume any issue with dependency wiring will throw an exception during test setup. It doesn't — you get an NPE during test execution instead.
- Typos in Mock Field Names: Declaring a mock with a typo like auditLoger when the class field is auditLogger. Mockito can't match by name, so it leaves the field null.
- Not Using @ExtendWith: Forgetting @ExtendWith(MockitoExtension.class) means Mockito doesn't process annotations, so all @Mock and @InjectMocks fields are null. The error looks like an injection failure but is actually a setup failure.
- Ignoring Constructor Injection: Continuing to use field injection in production code because it's familiar, not realizing constructor injection would prevent all these silent test failures.
Check your understanding
Answer these without looking back at the article.
- How does constructor injection make @InjectMocks more reliable?
- What is strict stubbing and how does MockitoExtension enable it?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.