Mockito Basics — Mocking Dependencies in Java

2 minute read

Real classes have dependencies — databases, APIs, email services. You can’t call those in unit tests. Mockito creates fake versions of dependencies so you can test your logic in isolation.


Why Mocking?

UserService depends on:
  ├── UserRepository   (database)
  ├── EmailService     (sends emails)
  └── AuditLogger      (writes logs)

Unit test for UserService should NOT:
  ✗ Connect to a real database
  ✗ Send real emails
  ✗ Write real log files

Instead, MOCK all dependencies.

Maven Dependencies

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>5.12.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>5.12.0</version>
    <scope>test</scope>
</dependency>

Your First Mock

The Code Under Test

public class UserService {

    private final UserRepository userRepository;
    private final EmailService emailService;

    public UserService(UserRepository userRepository, EmailService emailService) {
        this.userRepository = userRepository;
        this.emailService = emailService;
    }

    public User createUser(String name, String email) {
        if (userRepository.existsByEmail(email)) {
            throw new DuplicateEmailException("Email already exists");
        }
        User user = new User(name, email);
        User saved = userRepository.save(user);
        emailService.sendWelcomeEmail(saved.getEmail());
        return saved;
    }
}

The Test

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.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @Mock
    private EmailService emailService;

    @InjectMocks
    private UserService userService;

    @Test
    void shouldCreateUserSuccessfully() {
        // Arrange
        when(userRepository.existsByEmail("alice@test.com")).thenReturn(false);
        when(userRepository.save(any(User.class)))
            .thenReturn(new User(1L, "Alice", "alice@test.com"));

        // Act
        User result = userService.createUser("Alice", "alice@test.com");

        // Assert
        assertEquals("Alice", result.getName());
        assertEquals(1L, result.getId());
        verify(emailService).sendWelcomeEmail("alice@test.com");
    }
}

Key Annotations

Annotation Purpose
@ExtendWith(MockitoExtension.class) Enables Mockito annotations in JUnit 5
@Mock Creates a mock instance
@InjectMocks Creates real instance, injects @Mock fields
@Spy Partial mock (real methods unless stubbed)
@Captor Captures arguments passed to mocks

Mock Default Behavior

Mocks return safe defaults — no real logic executes:

Return Type Default
Object null
int, long, etc. 0
boolean false
Collection Empty collection
Optional Optional.empty()
String null
@Test
void mockDefaultBehavior() {
    // Nothing stubbed — returns defaults
    assertNull(userRepository.findById(1L));        // null
    assertFalse(userRepository.existsByEmail("x")); // false
    assertEquals(0, userRepository.count());         // 0
}

Creating Mocks Without Annotations

// Option 1: Mockito.mock()
UserRepository mockRepo = mock(UserRepository.class);
EmailService mockEmail = mock(EmailService.class);
UserService service = new UserService(mockRepo, mockEmail);

// Option 2: @Mock annotations (preferred — less boilerplate)

@InjectMocks — How It Works

@Mock UserRepository userRepository;
@Mock EmailService emailService;

@InjectMocks UserService userService;
// Equivalent to: new UserService(userRepository, emailService)

Mockito tries injection in this order:

  1. Constructor injection (preferred)
  2. Setter injection
  3. Field injection

Best practice: Use constructor injection in your production code. It’s explicit and testable.


Mock vs Stub vs Fake

Term Definition Example
Mock Records interactions, verifiable Mockito @Mock
Stub Returns canned responses when(...).thenReturn(...)
Fake Working implementation (simplified) In-memory database
Spy Real object, selectively overridden Mockito @Spy

In practice, Mockito mocks are used for both mocking and stubbing.


Complete Example

@ExtendWith(MockitoExtension.class)
class OrderServiceTest {

    @Mock private OrderRepository orderRepository;
    @Mock private PaymentGateway paymentGateway;
    @Mock private NotificationService notificationService;

    @InjectMocks private OrderService orderService;

    @Test
    void shouldPlaceOrderSuccessfully() {
        // Arrange
        Order order = new Order("ORD-001", new BigDecimal("99.99"));
        when(paymentGateway.charge(any(), any())).thenReturn(true);
        when(orderRepository.save(any())).thenReturn(order);

        // Act
        Order result = orderService.placeOrder(order);

        // Assert
        assertNotNull(result);
        verify(paymentGateway).charge(eq("ORD-001"), eq(new BigDecimal("99.99")));
        verify(notificationService).sendOrderConfirmation("ORD-001");
        verify(orderRepository).save(order);
    }

    @Test
    void shouldThrowWhenPaymentFails() {
        Order order = new Order("ORD-002", new BigDecimal("50.00"));
        when(paymentGateway.charge(any(), any())).thenReturn(false);

        assertThrows(PaymentFailedException.class,
            () -> orderService.placeOrder(order));

        verify(orderRepository, never()).save(any());
        verify(notificationService, never()).sendOrderConfirmation(any());
    }
}

Common Mistakes

Mistake Fix
Forgetting @ExtendWith(MockitoExtension.class) Mocks stay null without it
Stubbing unused methods Mockito strict mode will warn
Mocking the class under test Mock dependencies, not the subject
Using @InjectMocks with @Mock on same type They serve different purposes

Key Takeaways

  1. Mock dependencies, not the class you’re testing.
  2. @Mock creates fakes, @InjectMocks wires them together.
  3. Mocks return safe defaults (null, 0, false, empty).
  4. Use constructor injection in production code for easy testability.
  5. @ExtendWith(MockitoExtension.class) is required for JUnit 5.

What’s Next?

Next: Mocking and Stubbing — when/thenReturn, argument matchers, verify, void methods, and consecutive calls.

Updated: