Verifying Method Calls with Mockito

Illustration for Verifying Method Calls with Mockito
By Last updated:

When writing unit tests, it’s not enough to just check return values. Sometimes, you need to verify whether a dependency method was called, how many times it was called, and with which arguments. Mockito provides a powerful verify() API for this purpose.

This tutorial explores method call verification in Mockito, including common scenarios, advanced usage, and best practices for writing maintainable unit tests.


Why Verify Method Calls?

  • Ensure interactions happen: Validate if services are invoked as expected.
  • Detect unwanted calls: Prevent accidental side effects.
  • Improve confidence: Guarantee correct control flow.
  • Test collaboration: Focus on how classes interact, not just results.

Think of verification like checking the black box flight recorder — you want to confirm the right actions were taken, not just the final outcome.


Example: User Registration

Class Under Test

class NotificationService {
    void sendEmail(String user, String message) {
        System.out.println("Email sent to " + user);
    }
}

class UserService {
    private final NotificationService notificationService;

    UserService(NotificationService notificationService) {
        this.notificationService = notificationService;
    }

    void registerUser(String user) {
        // Registration logic...
        notificationService.sendEmail(user, "Welcome!");
    }
}

Basic Verification with verify()

import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;

class UserServiceTest {

    @Test
    void shouldSendEmailOnRegistration() {
        NotificationService mockNotification = mock(NotificationService.class);
        UserService userService = new UserService(mockNotification);

        userService.registerUser("alice@example.com");

        verify(mockNotification).sendEmail("alice@example.com", "Welcome!");
    }
}

Here, we confirm that sendEmail() was called with the right arguments.


Verifying Call Counts

Using times()

verify(mockNotification, times(1)).sendEmail("alice@example.com", "Welcome!");

Using never()

verify(mockNotification, never()).sendEmail("bob@example.com", "Welcome!");

Using atLeastOnce()

verify(mockNotification, atLeastOnce()).sendEmail(anyString(), anyString());

Using atMost()

verify(mockNotification, atMost(2)).sendEmail(anyString(), anyString());

Argument Matchers with verify()

Mockito allows flexible argument checking:

verify(mockNotification).sendEmail(eq("alice@example.com"), anyString());

Or custom logic:

verify(mockNotification).sendEmail(anyString(), argThat(msg -> msg.contains("Welcome")));

Verifying Order of Calls

Sometimes, the sequence matters. Mockito provides InOrder:

InOrder inOrder = inOrder(mockNotification);
userService.registerUser("alice@example.com");
userService.registerUser("bob@example.com");

inOrder.verify(mockNotification).sendEmail("alice@example.com", "Welcome!");
inOrder.verify(mockNotification).sendEmail("bob@example.com", "Welcome!");

This ensures emails were sent in the expected order.


Advanced Usage: verifyNoMoreInteractions()

verify(mockNotification).sendEmail("alice@example.com", "Welcome!");
verifyNoMoreInteractions(mockNotification);

This guarantees no additional, unintended method calls happened.


Best Practices

  • Verify only meaningful interactions — don’t over-verify.
  • Use argument matchers for flexibility.
  • Verify order only when sequence is critical.
  • Combine verification with assertions for stronger tests.
  • Avoid verifying private/internal methods — focus on external behavior.

Mockito + Testcontainers

Mockito verifies interactions in unit tests, while Testcontainers validates behavior in integration tests with real systems.

Example: verify method calls with mocks, then run integration tests using PostgreSQL Testcontainer:

import org.testcontainers.containers.PostgreSQLContainer;

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

Version Tracker

  • JUnit 4 → JUnit 5: Mockito works seamlessly with Jupiter extensions.
  • Mockito Updates: New features include static method mocking and better verification.
  • Testcontainers Growth: Expanded support for databases and message queues alongside mocks.

Conclusion & Key Takeaways

Verifying method calls with Mockito ensures your code interacts with dependencies as expected. From verify() basics to advanced order verification, Mockito offers tools to make tests accurate and maintainable.

Key Takeaways:

  • Use verify() to confirm interactions.
  • Control call counts with times(), never(), atLeastOnce().
  • Validate arguments using any(), eq(), argThat().
  • Ensure sequence with InOrder.
  • Use verifyNoMoreInteractions() to detect unnecessary calls.

FAQ

1. What’s the difference between verify() and assertions?
verify() checks interactions; assertions check results.

2. Can I verify static method calls in Mockito?
Yes, Mockito 3.4+ supports mockStatic() with verify().

3. How do I ensure a method was never called?
Use verify(mock, never()).

4. Can I verify partial mocks (spies)?
Yes, verify() works with spies as well.

5. Should I verify all method calls?
No, verify only meaningful interactions.

6. What’s the difference between atLeastOnce() and times(1)?
Both can mean one call, but atLeastOnce() allows more.

7. Can I check the order of multiple mocks?
Yes, use InOrder with multiple mocks.

8. How do I handle overloaded methods in verify()?
Use argument matchers (eq(), any()) to avoid ambiguity.

9. What happens if verification fails?
Mockito throws an AssertionError with details.

10. Should I migrate to JUnit 5 for Mockito?
Yes, JUnit 5 provides better integration and extension support.