Manual Constructor Injection in Tests
Fast recall
Quick revision
Core answer
Interview-ready guide
Interview answer
To test a class with constructor injection without using at-InjectMocks, you just create the test subject manually by calling its constructor.
mock calls. Then, in the at-BeforeEach method, you instantiate the service by calling its constructor and passing the mocks as arguments.
For example, if OrderService has a constructor that takes PaymentGateway and InventoryRepository, you'd write orderService equals new OrderService with paymentGateway and inventoryRepo as parameters. The advantage is that this wiring is completely explicit. Anyone reading the test can see exactly which mock goes where.
If you pass the wrong type or forget an argument, the compiler catches it immediately — you don't have to wait for a runtime error. This approach eliminates the silent failure problem with at-InjectMocks, where injection fails but you only discover it when the test throws a NullPointerException. You still use at-Mock annotations to create the mocks because MockitoExtension handles initialization and cleanup automatically.
The manual construction only replaces the at-InjectMocks step. I find this pattern especially useful when I need different configurations of the same service across tests. Instead of relying on at-InjectMocks to figure out the wiring, I just create the service with the exact mocks I need for each test.
It's a few extra lines of code, but it makes the test self-documenting and much easier to debug.
Manual Constructor Injection in Tests
Direct Answer
Create the mocks with @Mock or Mockito.mock(), then pass them directly to the class constructor in @BeforeEach — no @InjectMocks needed, and the wiring is explicit and compile-time checked.
Code Example
@ExtendWith(MockitoExtension.class)
class OrderServiceExplicitTest {
@Mock private PaymentGateway paymentGateway;
@Mock private InventoryRepository inventoryRepo;
@Mock private EmailSender emailSender;
private OrderService orderService;
@BeforeEach
void setUp() {
// Explicit constructor call - no @InjectMocks magic
orderService = new OrderService(paymentGateway, inventoryRepo, emailSender);
}
@Test
void shouldProcessOrderWhenPaymentSucceeds() {
var order = new Order(1L, List.of("item1"), 50.0);
when(inventoryRepo.reserve(order.getItems())).thenReturn(true);
when(paymentGateway.charge(order.getTotal())).thenReturn(true);
var result = orderService.processOrder(order);
assertThat(result).isTrue();
verify(emailSender).sendConfirmation(order);
}
@Test
void shouldHandlePaymentFailure() {
var order = new Order(2L, List.of("item2"), 100.0);
when(paymentGateway.charge(order.getTotal())).thenReturn(false);
var result = orderService.processOrder(order);
assertThat(result).isFalse();
verify(emailSender, never()).sendConfirmation(any());
}
}
Common Mistakes & Pitfalls
- Forgetting @ExtendWith: Even when manually constructing the service, you still need @ExtendWith(MockitoExtension.class) to process @Mock annotations. Without it, all mocks are null.
- Creating New Mocks in setUp: Calling Mockito.mock() inside @BeforeEach without using @Mock annotations loses the automatic cleanup and reset that MockitoExtension provides between tests.
- Over-Engineering Simple Tests: Using explicit construction for every single test when @InjectMocks would work fine, adding unnecessary boilerplate. Use explicit construction when it solves a real problem, not as dogma.
Check your understanding
Answer these without looking back at the article.
- What is the risk of @InjectMocks when you add a new dependency to a service?
- Can you use @InjectMocks with constructor injection and setter injection simultaneously?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.