Injecting Mocks with @Mock and @InjectMocks Annotations

Learn how to use @Mock and @InjectMocks in Mockito for dependency injection in JUnit 5 tests. Master setup, examples, and best practices for unit testing

By Updated Java + Backend
Illustration for Injecting Mocks with @Mock and @InjectMocks Annotations

When writing unit tests, we often need to mock dependencies and inject them into the class under test. While you can do this manually, Mockito provides powerful annotations like @Mock and @InjectMocks to simplify the process.

In this tutorial, we’ll explore how to use @Mock and @InjectMocks in Mockito, their differences, setup, and best practices.


Why Use @Mock and @InjectMocks?

  • Simplify Test Setup: Avoid repetitive manual mocking and constructor injection.
  • Readable Tests: Annotations make dependencies and injection explicit.
  • Maintainable Code: Reduces boilerplate setup in large test classes.
  • Improved CI/CD Reliability: Consistent initialization across test runs.

Think of @Mock as casting actors for a play, and @InjectMocks as handing them scripts inside the main scene.


Example: User Service with Dependency

Class Under Test

class EmailService {
    void send(String email, String message) {
        System.out.println("Sending email to " + email);
    }
}

class UserService {
    private final EmailService emailService;

    UserService(EmailService emailService) {
        this.emailService = emailService;
    }

    void registerUser(String email) {
        // Registration logic...
        emailService.send(email, "Welcome!");
    }
}

Using @Mock and @InjectMocks

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.mockito.Mockito.verify;

@ExtendWith(MockitoExtension.class)
class UserServiceTest {

    @Mock
    private EmailService emailService; // Creates a mock

    @InjectMocks
    private UserService userService;  // Injects mock into UserService

    @Test
    void shouldSendWelcomeEmailOnRegistration() {
        userService.registerUser("alice@example.com");

        verify(emailService).send("alice@example.com", "Welcome!");
    }
}

Here:

  • @Mock creates a mock of EmailService.
  • @InjectMocks automatically injects the mock into UserService.

How Injection Works

Mockito tries different strategies in order:

  1. Constructor Injection (preferred if a suitable constructor is found).
  2. Setter Injection (if setters exist).
  3. Field Injection (as a last resort).

Manual Mocking vs @InjectMocks

Without @InjectMocks

@Test
void manualInjection() {
    EmailService mockEmail = mock(EmailService.class);
    UserService userService = new UserService(mockEmail);
    userService.registerUser("bob@example.com");

    verify(mockEmail).send("bob@example.com", "Welcome!");
}

With @InjectMocks

@InjectMocks
private UserService userService;

Much cleaner and reduces boilerplate.


Combining with @BeforeEach

@ExtendWith(MockitoExtension.class)
class UserServiceTest {

    @Mock
    private EmailService emailService;

    @InjectMocks
    private UserService userService;

    @BeforeEach
    void init() {
        // Additional setup if needed
    }
}

This ensures each test starts with fresh mocks.


Best Practices

  • Use @InjectMocks for classes with dependencies.
  • Prefer constructor injection in production code — works best with Mockito.
  • Avoid overusing field injection — can lead to fragile tests.
  • Keep tests focused — inject only necessary mocks.
  • Combine verify() with stubbing (when()) for complete coverage.

Mockito + Testcontainers Example

While @Mock and @InjectMocks simplify unit tests, Testcontainers help with integration tests using real dependencies.

import org.testcontainers.containers.PostgreSQLContainer;

@Test
void shouldStartDatabase() {
    try (PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")) {
        postgres.start();
        assert postgres.isRunning();
    }
}

Together, they provide a strong hybrid testing strategy.


Version Tracker

  • JUnit 4 → JUnit 5: Mockito switched from @RunWith(MockitoJUnitRunner.class) to @ExtendWith(MockitoExtension.class).
  • Mockito Updates: Improved injection strategies and reduced boilerplate.
  • Testcontainers Ecosystem: Growing support for real dependency validation.

Conclusion & Key Takeaways

@Mock and @InjectMocks make dependency injection in tests easier, cleaner, and more maintainable. They are essential for scalable unit testing in Java.

Key Takeaways:

  • @Mock creates mock objects.
  • @InjectMocks injects mocks automatically.
  • Prefer constructor injection for better testability.
  • Use annotations to reduce boilerplate.
  • Combine with Testcontainers for full coverage.

FAQ

1. What’s the difference between @Mock and @InjectMocks?
@Mock creates mock objects, while @InjectMocks injects them into the class under test.

2. Do I always need @InjectMocks?
No, you can inject manually, but @InjectMocks reduces boilerplate.

3. Which injection strategy does Mockito prefer?
Constructor injection, then setters, then fields.

4. Can I use multiple @InjectMocks in one test?
Yes, but each should represent a different class under test.

5. Does @InjectMocks work with final fields?
No, final fields cannot be injected.

6. Should I combine @Mock with @Spy?
Only when partial mocking is required.

7. Do mocks persist across tests?
No, fresh mocks are created for each test run.

8. What’s the difference between JUnit 4 and 5 setup?
JUnit 5 uses @ExtendWith(MockitoExtension.class) instead of runners.

9. Can I mock static methods with @Mock?
No, use mockStatic() for static methods.

10. How does this work in CI/CD pipelines?
Annotations ensure consistent, repeatable test setups across builds.

Part of a Series

This tutorial is part of our Java Testing Junit Mockito Testcontainers . Explore the full guide for related topics, explanations, and best practices.

View all tutorials in this series →