Skip to content

Mockito — Mocking, Stubs, Verify, BDDMockito, ArgumentCaptor, and Spy

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Mockito. We cover key concepts, practical examples, and best practices to help you master this topic.

Mockito is the most popular Java mocking framework, enabling creation of mock objects for isolating code under test. Mocks simulate the behavior of real dependencies — a mock Repository returns test data without accessing a database, and a mock HTTP client returns a canned response without making network calls.

What You'll Learn

  • Creating mocks with @Mock and Mockito.mock()
  • Stubbing with when/thenReturn and doThrow/when
  • Verifying interactions with verify
  • BDDMockito for behavior-driven development style
  • ArgumentCaptor for capturing method arguments
  • @Spy for partial mocking

Why It Matters

Unit tests should test one unit of code in isolation. Without mocking, a test for a service class becomes an integration test that depends on databases, APIs, and file systems — making tests slow, flaky, and hard to maintain.

Real-World Use

Mockito is used in virtually every Java project with automated tests. Spring Boot includes spring-boot-starter-test with Mockito pre-configured.


Setting Up Mockito

// Maven
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>5.6.0</version>
    <scope>test</scope>
</dependency>

Creating Mocks

Using Annotations

@ExtendWith(MockitoExtension.class)
class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @Test
    void shouldFindUser() {
        when(userRepository.findById(1L)).thenReturn(Optional.of(new User("Alice")));
        User user = userService.getUser(1L);
        assertEquals("Alice", user.getName());
    }
}

@InjectMocks injects the @Mock fields into the UserService constructor (or setters/fields).

Without Annotations

UserRepository mockRepo = Mockito.mock(UserRepository.class);
UserService service = new UserService(mockRepo);

Stubbing

Standard Stubbing

// Return a value
when(repository.findById(1L)).thenReturn(Optional.of(user));

// Throw an exception
when(repository.save(any())).thenThrow(new DataIntegrityViolationException("Duplicate"));

// Return different values on successive calls
when(repository.findById(anyLong()))
    .thenReturn(Optional.of(user))  // first call
    .thenThrow(new RuntimeException()); // second call

Void Methods

doNothing().when(repository).delete(anyLong());
doThrow(new RuntimeException("Delete failed")).when(repository).delete(1L);

Argument Matchers

when(repository.findById(1L)).thenReturn(Optional.of(user));
when(repository.findById(anyLong())).thenReturn(Optional.empty());
when(repository.findByName(anyString())).thenReturn(List.of(user));
when(repository.save(argThat(u -> u.getAge() > 18))).thenReturn(user);

Available matchers: any(), anyInt(), anyString(), anyList(), eq(value), argThat(predicate).

Verification

Verify that specific interactions occurred:

@Test
void shouldSaveUser() {
    userService.createUser("Bob");
    verify(repository).save(any(User.class));
}

@Test
void shouldCallDeleteExactlyOnce() {
    userService.deleteUser(1L);
    verify(repository, times(1)).delete(1L);
}

// Never called
verify(repository, never()).delete(anyLong());

// Called at least once
verify(repository, atLeastOnce()).save(any());

// No more interactions
verifyNoMoreInteractions(repository);

// Order verification
InOrder inOrder = inOrder(repository, emailService);
inOrder.verify(repository).save(any());
inOrder.verify(emailService).sendWelcome(any());

BDDMockito

Behavior-Driven Development style uses given/willReturn/then:

import static org.mockito.BDDMockito.*;

@Test
void shouldReturnUser() {
    // Given
    given(userRepository.findById(1L)).willReturn(Optional.of(user));

    // When
    User result = userService.getUser(1L);

    // Then
    then(userRepository).should().findById(1L);
    assertEquals("Alice", result.getName());
}

BDDMockito aligns with the Given/When/Then structure of BDD tests.

ArgumentCaptor

Capture arguments passed to mock methods for further assertions:

@Test
void shouldSendEmailWithCorrectContent() {
    // When
    userService.registerUser("Alice", "alice@example.com");

    // Then
    ArgumentCaptor<Email> captor = ArgumentCaptor.forClass(Email.class);
    verify(emailService).send(captor.capture());

    Email captured = captor.getValue();
    assertEquals("alice@example.com", captured.getTo());
    assertEquals("Welcome!", captured.getSubject());
}

Spy — Partial Mocking

A spy wraps a real object, allowing you to stub specific methods while keeping real behavior for others:

@Test
void shouldUseSpy() {
    List<String> list = new ArrayList<>();
    List<String> spy = Mockito.spy(list);

    // Stub size() to return 100
    doReturn(100).when(spy).size();

    // Real behavior for other methods
    spy.add("A");
    spy.add("B");

    assertEquals(100, spy.size()); // stubbed
    assertEquals("A", spy.get(0)); // real
}

Common Mistakes

  1. Not using @ExtendWith(MockitoExtension.class). Without this, @Mock and @InjectMocks are not processed.
  2. Stubbing void methods with when(). Use doThrow()/doNothing() for void methods.
  3. Mixing matchers and concrete values incorrectly. If you use matchers for one argument, all arguments must use matchers:
    // WRONG
    when(repository.save(any(), "fixed"));
    // RIGHT
    when(repository.save(any(), eq("fixed")));
    
  4. Over-mocking. If a test requires 5+ mocks, consider if the class under test has too many dependencies.
  5. Verifying interactions that do not matter. Only verify interactions that are essential to the test's scenario.

Practice Questions

1. What is the difference between @Mock and @InjectMocks?
@Mock creates a mock instance. @InjectMocks creates a real instance and injects the mocks into it (via constructor, setter, or field).

2. What does verify(mock, times(2)).method() do?
It verifies that method was called exactly twice on the mock. Fails if called more or fewer times.

3. How do you capture a method argument in Mockito?
Use ArgumentCaptor. Create a captor for the type, call verify(mock).method(captor.capture()), then inspect captor.getValue().

4. What is the difference between a mock and a spy?
A mock has no real behavior — all methods return defaults (0, null, false). A spy wraps a real object; unstubbed methods execute real code.

5. How do you stub a void method to throw an exception?
doThrow(new RuntimeException()).when(mock).method().

Challenge Question:
Write a test for an OrderService that depends on InventoryService, PaymentService, and NotificationService. Use Mockito to stub InventoryService.checkStock() returning true, PaymentService.charge() returning a PaymentResult, and verify that NotificationService.sendConfirmation() is called once. Use ArgumentCaptor to verify the notification content.

FAQ

What is the difference between `when().thenReturn()` and `doReturn().when()`?

For methods that return a value, both work. doReturn().when() is recommended when the method should not be executed (e.g., stubbing a spy). For void methods, only doReturn() works.

Can I mock a final class?

Yes, since Mockito 2.1.0. add mockito-inline or configure src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker with mock-maker-inline.

What is a `strict stub`?

In Mockito 3+, lenient vs strict stubs control whether unused stubs cause test failure. Use @MockitoSettings(strictness = Strictness.LENIENT) or lenient() on individual stubs.

Can I mock a static method?

Yes, with Mockito 3.4.0+ using MockedStatic. Wrap in try-with-resources: try (MockedStatic<Utility> mocked = Mockito.mockStatic(Utility.class)) { ... }.

What is the difference between `verifyNoMoreInteractions()` and `verifyZeroInteractions()`?

verifyNoMoreInteractions() passes if all interactions have been verified. verifyZeroInteractions() (deprecated in favor of verifyNoInteractions()) checks that no interactions occurred at all.

Mini Project

Write comprehensive Mockito tests for a LibraryService:

  1. LibraryService depends on BookRepository, MemberRepository, and EmailService
  2. Test borrowBook: stub repository methods, verify interactions
  3. Test borrowBook when book is not available — stub to return Optional.empty()
  4. Test returnBook: verify email is sent with correct content using ArgumentCaptor
  5. Test getOverdueBooks: stub a repository method that throws an exception
  6. Use BDDMockito style (given/willReturn/then/should)
  7. Use @InjectMocks and @Mock annotations
  8. Add a spy test for a partial mock scenario

What's Next

Unit tests validate individual components. Integration tests validate the system as a whole. Lesson 49 covers integration testing — Testcontainers for database testing, @SpringBootTest for application context loading, and embedded databases for fast in-memory testing.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro