Home Tutorials Training Consulting Books Company Contact us


Get more...

Lars Vogel, (©) 2012 - 2025 vogella GmbH :author_twitter_handle: vogella :revnumber: 3.0 :revdate: 29.08.2025 :vgwort: Mockito :exercise_solution: :mockitoversion: 5.20.0

This tutorial explains the usage of the Mockito framework for writing software tests with JUnit 5 in Java.

1. Prerequisites

This tutorial introduces the usage of Mockito for JUnit tests. If you are not familiar with JUnit, please read first the JUnit Tutorial.

2. Using Mockito for mocking objects in unit tests

Mockito is a popular open-source framework for mocking objects in software tests. Mockito greatly simplifies the development of tests for classes with external dependencies by providing clean, readable mocking syntax.

2.1. What are mock objects?

A mock object is a dummy implementation for an interface or a class that simulates the behavior of real objects in a controlled way. Mock objects allow you to:

  • Define the output of specific method calls

  • Verify that methods were called with expected parameters

  • Isolate the code under test from external dependencies

  • Test edge cases and error conditions easily

This approach simplifies test setup and makes tests more focused and reliable.

mockitousagevisualization

2.2. Why use Mockito?

Mockito provides several advantages for testing:

  • Clean syntax: Readable and intuitive API for creating and configuring mocks

  • Comprehensive features: Support for argument verification, spy objects, and partial mocking

  • Modern capabilities: Recent versions can mock static methods, final classes, and constructors

  • Flexible verification: Both state-based and behavior-based testing approaches

  • Excellent integration: Works seamlessly with JUnit 5 and other testing frameworks

2.3. Mockito capabilities and limitations

Modern Mockito versions (5.x+) support mocking: * Regular classes and interfaces * Static methods * Final classes and methods * Constructors (using MockedConstruction)

Limitations: * Private methods cannot be mocked directly (they are not visible to tests) * Some native methods may not be mockable

See Mockito limitations for complete details.

2.4. State testing vs behavior testing

Mockito enables both testing approaches:

2.5. State testing vs behavior testing

Mockito enables both testing approaches:

// State testing - verifies the outcome/result
@Test
void testEmailNotificationSent() {
    NotificationService service = new NotificationService(emailClient);

    service.sendWelcomeEmail("user@example.com");

    // Verify the final state or return value
    assertTrue(service.getLastEmailStatus().isSuccess());
}

// Behavior testing - verifies method interactions
@Test
void testEmailClientCalledCorrectly() {
    NotificationService service = new NotificationService(emailClientMock);

    service.sendWelcomeEmail("user@example.com");

    // Verify specific method calls occurred
    verify(emailClientMock).sendEmail(
        eq("user@example.com"),
        eq("Welcome!"),
        contains("Welcome to our platform")
    );
}

Both approaches have their place in testing. State testing focuses on outcomes, while behavior testing ensures correct interaction with dependencies.

For further information about testing with Java see:

3. Adding Mockito to a project

Using the Mockito libraries should be done with a modern dependency system like Maven or Gradle. All modern IDEs (Eclipse, Visual Studio Code, IntelliJ) support both Maven and Gradle.

The following contains detailed descriptions for your environment, pick the one which is relevant for you. The latest version of Mockito can be found via https://search.maven.org/artifact/org.mockito/mockito-core.

Using Maven

To use Mockito in your Maven project, add the following dependency to your pom file. It assumes that you already added the dependencies for your test framework, e.g., JUnit 5.

<!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>{mockitoversion}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>{mockitoversion}</version>
    <scope>test</scope>
</dependency>

Use the latest version from https://mvnrepository.com/artifact/org.mockito/mockito-core instead of 3.11.2.

mockito-junit-jupiter` adds the MockitoExtension for JUnit 5.
Using Gradle for a Java project

To use Mockito in a Gradle project, add the following dependency to the build.gradle file. It assumes that you already added the dependencies for your test framework, e.g., JUnit 5.

dependencies {
    testImplementation 'org.mockito:mockito-core:{mockitoversion}'
    testImplementation 'org.mockito:mockito-junit-jupiter:{mockitoversion}'
    }
Using Mockito for an Android project

Add the following dependency to the Gradle build file:

dependencies {
    // ... more entries
    // required if you want to use Mockito for unit tests
    testImplementation 'org.mockito:mockito-core:{mockitoversion}'
    // required if you want to use Mockito for Android tests
    androidTestImplementation 'org.mockito:mockito-android:{mockitoversion}'
}
OSGi or Eclipse plug-in development

In OSGi or Eclipse plug-in/ RCP development you can use Maven dependencies via your target platform. See Using Java libraries for Eclipse / OSGi development tutorial.

4. Creating mock objects with the Mockito API

Mockito provides several methods to create mock objects:

  • Using the @ExtendWith(MockitoExtension.class) extension for JUnit 5 in combination with the @Mock annotation on fields

  • Using the static mock() method programmatically

  • Using the @Mock annotation with manual initialization

The MockitoExtension automatically initializes all @Mock annotated fields by calling MockitoAnnotations.openMocks(this) behind the scenes.

4.1. Practical example: Testing a user service

Let’s explore Mockito with a realistic example - a user service that manages user registration and interacts with a database and email service.

package com.vogella.junit5;

public class User {
    private String email;
    private String name;
    private boolean verified;

    public User(String email, String name) {
        this.email = email;
        this.name = name;
        this.verified = false;
    }

    // getters and setters
    public String getEmail() { return email; }
    public String getName() { return name; }
    public boolean isVerified() { return verified; }
    public void setVerified(boolean verified) { this.verified = verified; }
}
package com.vogella.junit5;

public interface UserRepository {
    void save(User user);
    User findByEmail(String email);
    boolean emailExists(String email);
}
package com.vogella.junit5;

public interface EmailService {
    boolean sendWelcomeEmail(String email, String name);
    boolean sendVerificationEmail(String email, String verificationCode);
}
package com.vogella.junit5;

public class UserService {

    private final UserRepository userRepository;
    private final EmailService emailService;

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

    public boolean registerUser(String email, String name) {
        // Check if user already exists
        if (userRepository.emailExists(email)) {
            return false;
        }

        // Create and save user
        User user = new User(email, name);
        userRepository.save(user);

        // Send welcome email
        return emailService.sendWelcomeEmail(email, name);
    }

    public User getUserByEmail(String email) {
        return userRepository.findByEmail(email);
    }
}

A unit test using Mockito which mocks the dependencies could look like the following.

package com.vogella.junit5;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

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

@ExtendWith(MockitoExtension.class)                     (1)
class UserServiceTest {

    @Mock
    UserRepository userRepository;                      (2)

    @Mock
    EmailService emailService;                          (3)

    @Test
    void testSuccessfulUserRegistration() {
        // Arrange: Configure mock behavior
        when(userRepository.emailExists("john@example.com")).thenReturn(false);  (4)
        when(emailService.sendWelcomeEmail("john@example.com", "John")).thenReturn(true);

        UserService userService = new UserService(userRepository, emailService);

        // Act: Execute the method under test
        boolean result = userService.registerUser("john@example.com", "John"); (5)

        // Assert: Verify the outcome
        assertTrue(result);                                                     (6)

        // Verify interactions with mocks
        verify(userRepository).save(any(User.class));                          (7)
        verify(emailService).sendWelcomeEmail("john@example.com", "John");
    }

    @Test
    void testUserRegistrationWithExistingEmail() {
        // Arrange: User already exists
        when(userRepository.emailExists("existing@example.com")).thenReturn(true);

        UserService userService = new UserService(userRepository, emailService);

        // Act & Assert
        assertFalse(userService.registerUser("existing@example.com", "Jane"));
    }
}
1 Enables Mockito extension for JUnit 5 to automatically initialize mocks
2 Creates a mock of UserRepository that will be injected into our test
3 Creates a mock of EmailService for testing email functionality
4 Configures the mock to return false when checking if email exists (new user scenario)
5 Executes the method we want to test with our mocked dependencies
6 Asserts that user registration was successful
7 Verifies that specific methods were called on our mocks with expected parameters
Static imports

Mockito provides a lot of static methods for mock and asserts. By adding the org.mockito.Mockito.*; static import, you can use these methods directly in your tests. Static imports allow you to call static members, i.e., methods and fields of a class directly without specifying the class.

Using static imports also greatly improves the readability of your test code.

5. Common use cases for Mockito

This section covers the most common scenarios where Mockito provides value in unit testing.

5.1. Testing services with external dependencies

One of the most common use cases for Mockito is testing service classes that depend on external systems like databases, web services, or file systems.

@ExtendWith(MockitoExtension.class)
class PaymentServiceTest {

    @Mock
    PaymentGateway paymentGateway;

    @Mock
    AuditService auditService;

    @Test
    void testSuccessfulPayment() {
        // Arrange
        when(paymentGateway.processPayment(anyDouble(), anyString()))
            .thenReturn(new PaymentResult(true, "TX123"));

        PaymentService service = new PaymentService(paymentGateway, auditService);

        // Act
        PaymentResult result = service.processPayment(100.0, "4111111111111111");

        // Assert
        assertTrue(result.isSuccess());
        assertEquals("TX123", result.getTransactionId());

        // Verify audit was called
        verify(auditService).logPayment(eq(100.0), eq("TX123"));
    }

    @Test
    void testPaymentFailure() {
        // Test error handling
        when(paymentGateway.processPayment(anyDouble(), anyString()))
            .thenReturn(new PaymentResult(false, "DECLINED"));

        PaymentService service = new PaymentService(paymentGateway, auditService);

        PaymentResult result = service.processPayment(100.0, "4111111111111111");

        assertFalse(result.isSuccess());
        verify(auditService).logPaymentFailure(eq(100.0), eq("DECLINED"));
    }
}

5.2. Argument verification and capturing

Mockito provides powerful argument verification capabilities to ensure methods are called with correct parameters.

@Test
void testArgumentVerification() {
    UserService userService = new UserService(userRepository, emailService);

    userService.registerUser("john@example.com", "John Doe");

    // Verify exact parameters
    verify(emailService).sendWelcomeEmail("john@example.com", "John Doe");

    // Verify with argument matchers
    verify(userRepository).save(argThat(user ->
        user.getEmail().equals("john@example.com") &&
        user.getName().equals("John Doe")
    ));

    // Capture arguments for complex verification
    ArgumentCaptor<User> userCaptor = ArgumentCaptor.forClass(User.class);
    verify(userRepository).save(userCaptor.capture());

    User capturedUser = userCaptor.getValue();
    assertEquals("john@example.com", capturedUser.getEmail());
    assertFalse(capturedUser.isVerified()); // New users start unverified
}

5.3. Testing exception scenarios

Mockito makes it easy to test how your code handles exceptions from dependencies.

@Test
void testDatabaseConnectionFailure() {
    // Simulate database failure
    when(userRepository.save(any(User.class)))
        .thenThrow(new RuntimeException("Database connection failed"));

    UserService userService = new UserService(userRepository, emailService);

    // Verify exception handling
    assertThrows(RuntimeException.class, () -> {
        userService.registerUser("test@example.com", "Test User");
    });

    // Ensure email is not sent when database fails
    verify(emailService, never()).sendWelcomeEmail(anyString(), anyString());
}

5.4. Testing asynchronous operations

When testing code that makes asynchronous calls, Mockito can help verify the correct callbacks are invoked.

@Test
void testAsynchronousEmailSending() {
    // Mock async email service
    doAnswer(invocation -> {
        String email = invocation.getArgument(0);
        Callback callback = invocation.getArgument(2);
        // Simulate async success
        callback.onSuccess("Email sent to " + email);
        return null;
    }).when(emailService).sendEmailAsync(anyString(), anyString(), any(Callback.class));

    NotificationService service = new NotificationService(emailService);

    boolean result = service.sendNotificationAsync("user@example.com", "Welcome!");

    assertTrue(result);
    verify(emailService).sendEmailAsync(eq("user@example.com"), eq("Welcome!"), any(Callback.class));
}

5.5. Partial mocking with spies

Sometimes you want to use the real object but override specific methods. This is where spies come in handy.

@Test
void testUserServiceWithSpy() {
    // Create a spy of the real UserService
    UserService userService = spy(new UserService(userRepository, emailService));

    // Mock only specific methods
    doReturn(true).when(userService).isValidEmail("test@example.com");

    // Real method calls will work, but isValidEmail is mocked
    boolean result = userService.registerUser("test@example.com", "Test User");

    assertTrue(result);
    verify(userService).isValidEmail("test@example.com");
}

5.6. Testing with multiple mock interactions

Complex scenarios often involve multiple interactions with the same mock in a specific order.

@Test
void testMultipleUserOperations() {
    UserService userService = new UserService(userRepository, emailService);

    // Setup multiple return values
    when(userRepository.emailExists(anyString()))
        .thenReturn(false)  // First check: email available
        .thenReturn(true);  // Second check: email now exists

    when(emailService.sendWelcomeEmail(anyString(), anyString()))
        .thenReturn(true);

    // First registration should succeed
    assertTrue(userService.registerUser("user1@example.com", "User One"));

    // Second registration with same email should fail
    assertFalse(userService.registerUser("user1@example.com", "User Two"));

    // Verify call order and count
    verify(userRepository, times(2)).emailExists("user1@example.com");
    verify(emailService, times(1)).sendWelcomeEmail(anyString(), anyString());
}

6. Configuring the return values of method calls on mock objects

Mockito allows you to configure the return values of methods called on mock objects via a fluent API. Unspecified method calls return "empty" values:

  • null for objects

  • 0 for numbers

  • false for boolean

  • empty collections for collections

This default behavior makes mocks safe to use without explicit configuration, but you’ll typically want to configure specific return values for your test scenarios.

The following examples demonstrate Mockito configuration patterns using a realistic UserService scenario. In real tests, you would use these techniques to test your actual business logic rather than just verifying mock behavior.

6.1. Using when().thenReturn() and when().thenThrow()

The when(…​.).thenReturn(…​.) method chain is the most common way to configure mock behavior. It allows you to specify return values for method calls with predefined parameters.

whenThenReturn10

You can also use argument matchers like anyString() or anyInt() to match any input of a specific type, or create more complex matching conditions.

If you specify multiple return values, they are returned in the order of specification until the last one is used. After that, the last specified value is returned for all subsequent calls.

The following demonstrates basic when(…​).thenReturn(…​.) configuration:

package com.vogella.junit5;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.when;

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

@ExtendWith(MockitoExtension.class) 
class UserServiceConfigurationTest {

    @Mock
    UserRepository userRepository;
    
    @Mock
    EmailService emailService;

    @Test
    void ensureEmailServiceReturnsConfiguredValue() {
        // Configure mock to return specific value
        when(emailService.sendWelcomeEmail("john@example.com", "John")).thenReturn(true);

        UserService userService = new UserService(userRepository, emailService);
        
        // Test that our mock configuration works
        assertTrue(emailService.sendWelcomeEmail("john@example.com", "John"));
    }
    
    @Test
    void testUserRepositoryMockConfiguration() {
        User mockUser = new User("test@example.com", "Test User");
        when(userRepository.findByEmail("test@example.com")).thenReturn(mockUser);
        
        UserService userService = new UserService(userRepository, emailService);
        User result = userService.getUserByEmail("test@example.com");
        
        assertEquals("test@example.com", result.getEmail());
        assertEquals("Test User", result.getName());
    }
}

Here are more advanced examples showing multiple return values and argument matching:

package com.vogella.junit5;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;

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

@ExtendWith(MockitoExtension.class)
class UserServiceAdvancedMockingTest {
    
    @Mock
    UserRepository userRepository;
    
    @Mock
    EmailService emailService;

    // demonstrates the return of multiple values
    @Test
    void testMultipleReturnValues() {
        // First call returns true, second returns false
        when(emailService.sendWelcomeEmail(anyString(), anyString()))
            .thenReturn(true)
            .thenReturn(false);
            
        // First call gets true
        assertTrue(emailService.sendWelcomeEmail("user1@example.com", "User1"));
        // Second call gets false
        assertFalse(emailService.sendWelcomeEmail("user2@example.com", "User2"));
    }

    // this test demonstrates how to return values based on the input
    @Test
    void testReturnValueDependentOnMethodParameter() {
        when(userRepository.emailExists("existing@example.com")).thenReturn(true);
        when(userRepository.emailExists("new@example.com")).thenReturn(false);
        
        UserService userService = new UserService(userRepository, emailService);
        
        // Test specific parameter matching
        assertTrue(userRepository.emailExists("existing@example.com"));
        assertFalse(userRepository.emailExists("new@example.com"));
    }
    
    // return a value based on argument matchers
    @Test
    void testReturnValueWithArgumentMatchers() {
        // Any email containing "test" will return false for email sending
        when(emailService.sendWelcomeEmail(contains("test"), anyString())).thenReturn(false);
        // Any other email will return true
        when(emailService.sendWelcomeEmail(any(), any())).thenReturn(true);
        
        // Test with argument matchers
        assertFalse(emailService.sendWelcomeEmail("test@example.com", "Test User"));
        assertTrue(emailService.sendWelcomeEmail("user@example.com", "Regular User"));
    }

    @Test 
    void testUserCreationBasedOnParameters() {
        // Return different users based on email parameter
        User testUser = new User("test@example.com", "Test User");
        User adminUser = new User("admin@example.com", "Admin User");
        
        when(userRepository.findByEmail("test@example.com")).thenReturn(testUser);
        when(userRepository.findByEmail("admin@example.com")).thenReturn(adminUser);
        
        UserService userService = new UserService(userRepository, emailService);
        
        assertEquals("Test User", userService.getUserByEmail("test@example.com").getName());
        assertEquals("Admin User", userService.getUserByEmail("admin@example.com").getName());
    }
}

The when(…​.).thenThrow(…​.) method can be used to simulate error conditions:

package com.vogella.junit5;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;

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

@ExtendWith(MockitoExtension.class)
class UserServiceExceptionTest {
    
    @Mock
    UserRepository userRepository;
    
    @Mock
    EmailService emailService;
    
    // demonstrates throwing exceptions from mocked methods
    @Test
    void testEmailServiceThrowsException() {
        // Configure mock to throw exception
        when(emailService.sendWelcomeEmail(anyString(), anyString()))
            .thenThrow(new RuntimeException("Email service unavailable"));

        UserService userService = new UserService(userRepository, emailService);
        
        // Configure repository to allow user creation
        when(userRepository.emailExists("test@example.com")).thenReturn(false);
        
        // Verify that exception is thrown during user registration
        RuntimeException exception = assertThrows(RuntimeException.class, () -> {
            userService.registerUser("test@example.com", "Test User");
        });

        assertEquals("Email service unavailable", exception.getMessage());
    }
    
    @Test
    void testRepositoryThrowsException() {
        // Mock repository to throw exception when checking email existence
        when(userRepository.emailExists(anyString()))
            .thenThrow(new RuntimeException("Database connection failed"));

        UserService userService = new UserService(userRepository, emailService);
        
        // Verify exception is propagated
        assertThrows(RuntimeException.class, () -> {
            userService.registerUser("test@example.com", "Test User");
        });
    }
}

6.2. doReturn().when() and doThrow().when()

The doReturn(…​).when(…​) method provides an alternative way to configure mock behavior. While when(…​.).thenReturn(…​.) is generally more readable, doReturn().when() is essential when working with spies.

6.2.1. Why use doReturn() instead of when().thenReturn()?

When using spy objects, when(…​.).thenReturn(…​.) actually calls the real method first, which can cause problems: - The real method might have side effects you want to avoid - The real method might throw exceptions - The real method might be slow or require external dependencies

doReturn().when() avoids calling the real method entirely, making it safer for spies.

package com.vogella.junit5;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

import java.util.ArrayList;
import java.util.List;

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

@ExtendWith(MockitoExtension.class)
class UserServiceSpyTest {
    
    @Mock
    UserRepository userRepository;
    
    @Mock 
    EmailService emailService;
    
    // demonstrates the use of doReturn with spies
    @Test
    void ensureSpyWorksWithUserService() {
        UserService userService = new UserService(userRepository, emailService);
        UserService spiedService = spy(userService);
        
        // Use doReturn to avoid calling the real method
        doReturn(true).when(spiedService).isValidEmail("test@example.com");
        
        // This calls the spied method which returns our configured value
        boolean isValid = spiedService.isValidEmail("test@example.com");
        
        assertTrue(isValid);
    }
    
    // demonstrates why doReturn is preferred over when().thenReturn() for spies
    @Test
    void testSpyWithDoReturnVsWhen() {
        List<String> list = new ArrayList<>();
        List<String> spiedList = spy(list);
        
        // This is safe - doesn't call the real method
        doReturn("mocked").when(spiedList).get(0);
        
        // This would be problematic with when().thenReturn() because 
        // it would call the real get(0) method on an empty list
        // when(spiedList.get(0)).thenReturn("mocked"); // Would throw IndexOutOfBoundsException
        
        assertEquals("mocked", spiedList.get(0));
    }
    
    @Test
    void testComplexObjectSpy() {
        // Create a real user service with real dependencies
        UserService realService = new UserService(userRepository, emailService);
        UserService spiedService = spy(realService);
        
        // Configure dependencies
        when(userRepository.emailExists("test@example.com")).thenReturn(false);
        when(emailService.sendWelcomeEmail("test@example.com", "Test User")).thenReturn(true);
        
        // Override only the validation method using doReturn
        doReturn(true).when(spiedService).isValidEmail("test@example.com");
        
        // Call the real method which uses our mocked dependencies and spied validation
        boolean result = spiedService.registerUser("test@example.com", "Test User");
        
        assertTrue(result);
    }
}

The doThrow().when() variant is particularly useful for configuring void methods to throw exceptions:

package com.vogella.junit5;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.verify;

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

@ExtendWith(MockitoExtension.class)
class UserServiceExceptionHandlingTest {
    
    @Mock
    UserRepository userRepository;
    
    @Mock
    EmailService emailService;
    
    @Test
    void testDoThrowWithVoidMethod() {
        // Configure mock to throw exception on void method
        doThrow(new RuntimeException("Database connection failed"))
            .when(userRepository).save(any(User.class));
        
        UserService userService = new UserService(userRepository, emailService);
        
        // Test that exception is properly propagated
        assertThrows(RuntimeException.class, () -> {
            User user = new User("test@example.com", "Test User");
            userRepository.save(user);
        });
    }
    
    @Test
    void testServiceHandlesRepositoryException() {
        // Setup: repository save throws exception
        doThrow(new RuntimeException("Database unavailable"))
            .when(userRepository).save(any(User.class));
        
        UserService userService = new UserService(userRepository, emailService);
        
        // Verify that user registration fails when database is unavailable
        assertThrows(RuntimeException.class, () -> {
            userService.registerUser("test@example.com", "Test User");
        });
        
        // Verify that save was attempted
        verify(userRepository).save(any(User.class));
    }
    
    @Test
    void testEmailServiceThrowsOnVoidMethod() {
        // Assume EmailService has a void method like sendBulkEmail
        doThrow(new RuntimeException("Email service temporarily unavailable"))
            .when(emailService).sendWelcomeEmail(anyString(), anyString());
        
        UserService userService = new UserService(userRepository, emailService);
        
        // Test exception handling in email operations
        RuntimeException exception = assertThrows(RuntimeException.class, () -> {
            userService.registerUser("test@example.com", "Test User");
        });
        
        assertEquals("Email service temporarily unavailable", exception.getMessage());
    }
}

7. Wrapping Java objects with Spy

@Spy or the spy() method can be used to wrap a real object. Every call, unless specified otherwise, is delegated to the object.

package com.vogella.mockito.spy;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.doReturn;

import java.util.LinkedList;
import java.util.List;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class MockitoSpyTest {

    @Spy
    List<String> spy = new LinkedList<>();

    @BeforeEach
    void setup() {
        // Alternative way of creating a spy
        // List<String> list = new LinkedList<>();
        // List<String> spy = spy(list);
    }

    @Test
    void testLinkedListSpyCorrect() {

        // when(spy.get(0)).thenReturn("foo");
        // would not work as the delegate it called so spy.get(0)
        // throws IndexOutOfBoundsException (list is still empty)

        // you have to use doReturn() for stubbing
        doReturn("foo").when(spy).get(0);

        assertEquals("foo", spy.get(0));
    }

}

7.1. Verify the calls on the mock objects

Mockito keeps track of all the method calls and their parameters to the mock object. You can use the verify() method on the mock object to verify that the specified conditions are met. For example, you can verify that a method has been called with certain parameters. This type of testing is sometimes called behavior testing. Behavior testing does not check the result of a method call, but it checks that a method is called with the right parameters.

package com.vogella.junit5;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

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

@ExtendWith(MockitoExtension.class) 
class UserServiceVerificationTest {

    @Mock
    UserRepository userRepository;
    
    @Mock
    EmailService emailService;

    @Test
    void testVerifyMethodCalls() {
        // Setup mocks
        when(userRepository.emailExists("test@example.com")).thenReturn(false);
        when(emailService.sendWelcomeEmail("test@example.com", "Test User")).thenReturn(true);
        
        UserService userService = new UserService(userRepository, emailService);
        
        // Execute methods under test
        userService.registerUser("test@example.com", "Test User");
        User user = userService.getUserByEmail("test@example.com");
        
        // Verify exact method calls with specific parameters
        verify(userRepository).emailExists(eq("test@example.com"));
        verify(userRepository).save(any(User.class));
        verify(emailService).sendWelcomeEmail(eq("test@example.com"), eq("Test User"));
        
        // Verify method was called exactly once (default)
        verify(userRepository, times(1)).save(any(User.class));
        
        // Verify findByEmail was called twice (once during registration check, once directly)
        verify(userRepository, times(2)).findByEmail("test@example.com");
        
        // Verify methods that should never be called
        verify(emailService, never()).sendVerificationEmail(anyString(), anyString());
        verify(userRepository, never()).emailExists("different@example.com");
        
        // Alternative verification options
        verify(userRepository, atLeastOnce()).emailExists("test@example.com");
        verify(userRepository, atLeast(1)).save(any(User.class));
        
        // Verify no other methods were called on these mocks
        // This should be called after all other verifications
        verifyNoMoreInteractions(userRepository, emailService);
    }
    
    @Test
    void testVerifyMultipleRegistrations() {
        UserService userService = new UserService(userRepository, emailService);
        
        // Setup different responses for different emails
        when(userRepository.emailExists("user1@example.com")).thenReturn(false);
        when(userRepository.emailExists("user2@example.com")).thenReturn(false);
        when(emailService.sendWelcomeEmail(anyString(), anyString())).thenReturn(true);
        
        // Register multiple users
        userService.registerUser("user1@example.com", "User One");
        userService.registerUser("user2@example.com", "User Two");
        
        // Verify each registration was processed correctly
        verify(userRepository).emailExists("user1@example.com");
        verify(userRepository).emailExists("user2@example.com");
        verify(userRepository, times(2)).save(any(User.class));
        verify(emailService, times(2)).sendWelcomeEmail(anyString(), anyString());
        
        // Verify specific parameters for each call
        verify(emailService).sendWelcomeEmail("user1@example.com", "User One");
        verify(emailService).sendWelcomeEmail("user2@example.com", "User Two");
    }
}

In case you do not care about the value, use the anyX, e.g., anyInt, anyString(), or any(YourClass.class) methods.

8. Using @InjectMocks for dependency injection via Mockito

You also have the @InjectMocks annotation that tries to do constructor, method or field dependency injection of mock objects in to other type. It does not require @Inject to be present and also does not try to be a full features dependency injection framework but is helpful to wire up objects to be tested.

For example, assume you have a class named ArticleManager with the following constructor:

public ArticleManager(User user, ArticleDatabase database) {
 // more code...
}

This class can be constructed via Mockito. The parameters to the constructor could be supplied via mock objects as demonstrated by the following code snippet.

package com.vogella.junit5;

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

@ExtendWith(MockitoExtension.class) 
class ArticleManagerTest {

    @Mock 
    ArticleDatabase database;
    
    @Mock 
    User user;
    
    @InjectMocks 
    private ArticleManager manager; (1)

    @Test 
    void shouldDoSomething() {
       // TODO perform some tests with this managers
    }
}
1 creates an instance of ArticleManager and injects the mocks into it

You find a full example of the usage of @InjectMocks in the exercises. Mockito can inject mocks either via constructor injection, setter injection, or property injection and in this order. So if ArticleManager would have a constructor that would only take User and setters for both fields, only the mock for User would be injected.

9. Capturing the arguments

The ArgumentCaptor class allows to access the arguments of method calls during the verification. This allows to capture these arguments of method calls and to use them for tests.

To run this example you need to add hamcrest-library to your project.

package com.vogella.junit5;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;
import static org.mockito.Mockito.verify;

import java.util.Arrays;
import java.util.List;

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

@ExtendWith(MockitoExtension.class)
public class MockitoArgumentCaptureTest {

    @Captor
    private ArgumentCaptor<List<String>> captor;

    @Test
    public final void shouldContainCertainListItem(@Mock List<String> mockedList) {
        var asList = Arrays.asList("someElement_test", "someElement");
        mockedList.addAll(asList);

        verify(mockedList).addAll(captor.capture());
        List<String> capturedArgument = captor.getValue();
        assertThat(capturedArgument, hasItem("someElement"));
    }
}

10. Using Answers for complex mocks

thenReturn returns a predefined value every time. With an Answer object you can calculate a response based on the arguments given to your stubbed method.

This can be useful if your stubbed method is supposed to call a function on one of the arguments or if your method is supposed to return the first argument to allow method chaining. There exists a static method for the latter. Also note that there a different ways to configure an answer:

import static org.mockito.AdditionalAnswers.returnsFirstArg;

@Test
public final void answerTest() {
    // with doAnswer():
    doAnswer(returnsFirstArg()).when(list).add(anyString());
    // with thenAnswer():
    when(list.add(anyString())).thenAnswer(returnsFirstArg());
    // with then() alias:
    when(list.add(anyString())).then(returnsFirstArg());
}

Or if you need to do a callback on your argument:

@Test
public final void callbackTest() {
    ApiService service = mock(ApiService.class);
    when(service.login(any(Callback.class))).thenAnswer(i -> {
        Callback callback = i.getArgument(0);
        callback.notify("Success");
        return null;
    });
}

It is even possible to mock a persistence service like an DAO, but you should consider creating a fake class instead of a mock if your Answers become too complex.

List<User> userMap = new ArrayList<>();
UserDao dao = mock(UserDao.class);
when(dao.save(any(User.class))).thenAnswer(i -> {
    User user = i.getArgument(0);
    userMap.add(user.getId(), user);
    return null;
});
when(dao.find(any(Integer.class))).thenAnswer(i -> {
    int id = i.getArgument(0);
    return userMap.get(id);
});

11. More on Mockito

11.1. Mocking final classes and static methods

With recent versions of Mockito it is possible to mock final classes and static methods. For example, if you have the following final class:

final class FinalClass {
    public final String finalMethod() { return "something"; }
}

You can mock it via the following code:

package com.vogella.junit5;

import static org.junit.jupiter.api.Assertions.assertNotNull;

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

@ExtendWith(MockitoExtension.class)
public class MockitoMockFinal {


    @Test
    public void testMockFinal(@Mock FinalClass finalMocked)  {
        assertNotNull(finalMocked);
    }

    @Test
    public void testMockFinalViaMockStatic()  {
        MockedStatic<FinalClass> mockStatic = Mockito.mockStatic(FinalClass.class);
        assertNotNull(mockStatic);
    }
}

Mockito also allows to mock static methods.

package com.vogella.junit5;

public class Utility {

    public static String getDatabaseConnection(String url) {
        return "http:///production/" + url;
    }
}
package com.vogella.junit5;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;

class MyUtilsTest {

    @Test
    void shouldMockStaticMethod() {
        MockedStatic<FinalClass> mockStatic = Mockito.mockStatic(FinalClass.class);
        try (MockedStatic<Utility> mockedStatic = Mockito.mockStatic(Utility.class)) {

            mockedStatic.when(() -> Utility.getDatabaseConnection(Mockito.eq("test"))).thenReturn("testing");
            mockedStatic.when(() -> Utility.getDatabaseConnection(Mockito.eq("prod"))).thenReturn("production");

            String result1 = Utility.getDatabaseConnection("test");

            assertEquals("testing", result1);
            String result2 = Utility.getDatabaseConnection("prod");
            assertEquals("production", result2);

        }

    }
}

11.2. Clean test code with the help of the strict stubs rule

The strict stubs rule helps you to keep your test code clean and checks for common oversights. It adds the following:

  • test fails early when a stubbed method gets called with different arguments than what it was configured for (with PotentialStubbingProblem exception).

  • test fails when a stubbed method is not called (with UnnecessaryStubbingException exception).

  • org.mockito.Mockito.verifyNoMoreInteractions(Object) also verifies that all stubbed methods have been called during the test

@Test
public void withoutStrictStubsTest() throws Exception {
    DeepThought deepThought = mock(DeepThought.class);

    when(deepThought.getAnswerFor("Ultimate Question of Life, The Universe, and Everything")).thenReturn(42);
    when(deepThought.otherMethod("some mundane thing")).thenReturn(null);

    System.out.println(deepThought.getAnswerFor("Six by nine"));

    assertEquals(42, deepThought.getAnswerFor("Ultimate Question of Life, The Universe, and Everything"));
    verify(deepThought, times(1)).getAnswerFor("Ultimate Question of Life, The Universe, and Everything");
}
// activate the strict subs rule
@Rule public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);

@Test
public void withStrictStubsTest() throws Exception {
    DeepThought deepThought = mock(DeepThought.class);

    when(deepThought.getAnswerFor("Ultimate Question of Life, The Universe, and Everything")).thenReturn(42);
    // this fails now with an UnnecessaryStubbingException since it is never called in the test
    when(deepThought.otherMethod("some mundane thing")).thenReturn(null);

    // this will now throw a PotentialStubbingProblem Exception since we usually do not want to call methods on mocks without configured behavior
    deepThought.someMethod();

    assertEquals(42, deepThought.getAnswerFor("Ultimate Question of Life, The Universe, and Everything"));
    // verifyNoMoreInteractions now automatically verifies that all stubbed methods have been called as well
    verifyNoMoreInteractions(deepThought);
}

12. Exercise: Create a new Maven or Gradle project with Mockito support

Create a new Maven or Gradle project named com.vogella.mockito.

Add the required libraries to your project depending on your build system.

Using Maven to add Mockito to your project

To use Mockito in your Maven project, add the following dependency to your pom file. It assumes that you already added the dependencies for your test framework, e.g., JUnit 5.

<!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>{mockitoversion}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>{mockitoversion}</version>
    <scope>test</scope>
</dependency>

Use the latest version from https://mvnrepository.com/artifact/org.mockito/mockito-core instead of 3.11.2.

mockito-junit-jupiter` adds the MockitoExtension for JUnit 5.
Using Gradle to add Mockito to your project

To use Mockito in a Gradle project, add the following dependency to the build.gradle file. It assumes that you already added the dependencies for your test framework, e.g., JUnit 5.

dependencies {
    testImplementation 'org.mockito:mockito-core:{mockitoversion}'
    testImplementation 'org.mockito:mockito-junit-jupiter:{mockitoversion}'
    }

You can now use Mockito in your project.

13. Exercise: Testing an API with Mockito and JUnit 5

13.1. Create an AudioManager API

Create the following classes which will be used in the following tests.

package com.vogella.mockito.audio;

public enum RINGER_MODE {
    RINGER_MODE_NORMAL, RINGER_MODE_SILENT
}
package com.vogella.mockito.audio;

public class AudioManager {
    private int volume = 50;
    private RINGER_MODE mode = RINGER_MODE.RINGER_MODE_SILENT;
    
    public RINGER_MODE getRingerMode() {
        return mode;
    }
    public int getStreamMaxVolume() {
        return volume;
    }
    public void setStreamVolume(int max) {
        volume = max;
    }
    public void makeReallyLoad() {
        if (mode.equals(RINGER_MODE.RINGER_MODE_NORMAL)) {
            setStreamVolume(100);
        }
    }
    
}
package com.vogella.mockito.audio;

public class MyApplication {

    public int getNumberOfThreads() {
        return 5;
    }

}
package com.vogella.mockito.audio;

public class ConfigureThreadingUtil {
    public static void configureThreadPool(MyApplication app){
        int numberOfThreads = app.getNumberOfThreads();
        // TODO use information to configure the thread pool


    }
}
package com.vogella.mockito.audio;

public class VolumeUtil {
    public static void maximizeVolume(AudioManager audioManager) {
        if (audioManager.getRingerMode() != RINGER_MODE.RINGER_MODE_SILENT) {
            int max = audioManager.getStreamMaxVolume();
            audioManager.setStreamVolume(max);
        }
        audioManager.setStreamVolume(50);
    }
}

13.2. Testing VolumeUtil

We want to test VolumeUtil using Mockito.

package com.vogella.mockito.audio;


import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

import org.junit.jupiter.api.Test;

class VolumeUtilTests {
    @Test
    void testNormalRingerIsMaximized(){
        // 1.) Ensure AudioManager gets mocked
        // 2.) configure Audiomanager to return RINGER_MODE_NORMAL if getRinderMode is called
        // 3.) configure Audiomanager to return 100 if getStreamMaxVolume() is called
        // 4.) call VolumeUtil.maximizeVolume with Audiomanager -> code under test
        // 5.) verify that setStreamVolume(100) was called on audioManager

    }

    @Test
    void testSilentRingerIsNotDisturbed() {
        // 1.) Ensure AudioManager gets mocked
        // 2.) configure audiomanager to return "RINGER_MODE_SILENT" if getRingerMode is called
        // 3.) call VolumeUtil.maximizeVolume with audio manager
        // 4.) verify that getRingerMode() is called on the mock
        // 5.) Ensure that nothing more was called


    }
}

The second test should find an error in VolumeUtil. Fix this in the original code.

13.3. Write a new Mockito test for ConfigureThreadingUtil

Write a new test that implements the following test comments using the following template.

package com.vogella.mockito.audio;

import org.junit.jupiter.api.Test;

class ConfigureThreadingUtilTests {
    @Test
    void ensureThatThreadPoolCanBeConfigured() {
        // mock MyApplication
        // call ConfigureThreadingUtil.configureThreadPool
        // verify that getNumberOfThreads was the only one called on app
    }
}