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.

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 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.

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
}
}