Mockito is an open-source and widely used mocking framework for Java applications. It allows developers to create mock objects, simulated objects that mimic the behavior of real ones in a controlled way.
By replacing real dependencies with mocks, Mockito enables testing code in isolation, without actually invoking real methods. This helps in writing clean, maintainable, and reliable unit tests, making it easier to define, control and verify the behavior of dependencies during testing.
Key Benefits of Mockito
- Isolated Testing: Test classes without relying on real dependencies.
- Faster Tests: Avoid slow operations like database or network calls.
- Cleaner Code: Reduce boilerplate with annotations like @Mock and @InjectMocks.
- Behavior Verification: Easily check if methods were called with expected arguments.
- Seamless Framework Support: Works seamlessly with JUnit 4, JUnit 5 and TestNG.
Problem that Mockito solved
Consider a scenario where you have a service class that depends on a database repository. Testing this service directly would require:
- Setting up a database connection
- Preparing test data
- Cleaning up after tests
With Mockito, you can mock the repository and focus only on testing the service logic without dealing with external dependencies.
Setting Up Mockito
Maven Dependency
XML
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.18.0</version>
<scope>test</scope>
</dependency>
Gradle Dependency
XML
testImplementation 'org.mockito:mockito-core:5.18.0'
Note: Always verify the latest available version of the library before adding it to your Maven or Gradle dependencies.
Core Concepts of Mockito
1. Mock Objects
Mock objects are fake implementations of real objects that simulate their behavior for testing purposes. They allow you to test a class in isolation by replacing its dependencies with controlled, predictable versions.
2. Stubbing
Stubbing is the process of defining what a mock object should return when a specific method is called. It’s used to simulate different scenarios such as returning fixed values, throwing exceptions, or mimicking slow responses.
3. Verification
Verification is the process of checking whether certain methods were called on mock objects during test execution. It ensures that the tested code interacts with its dependencies as expected like calling a method a specific number of times with given arguments.
Common Annotations in Mockito
1. @ExtendWith(MockitoExtension.class)
This is a JUnit 5 annotation that tells JUnit to enable Mockito’s annotation support (@Mock, @InjectMocks, @Spy) in the test class. Without it, Mockito won’t process these annotations automatically, and you’d have to initialize them manually.
Example:
Java
@ExtendWith(MockitoExtension.class) // Enables Mockito annotations
class ServiceTest {
}
2. @Mock
Creates a mock object automatically without calling mock(Class.class) manually.
Example:
Java
@ExtendWith(MockitoExtension.class)
class ServiceTest {
@Mock
Repository repo; //mock of Repository class
//Tests mocking behavior
@Test
void testMock() {
when(repo.getData()).thenReturn("mocked");
assertEquals("mocked", repo.getData());
}
}
3. @InjectMocks
Creates an instance of the class under test and automatically injects @Mock objects into it.
Example:
Java
@ExtendWith(MockitoExtension.class)
class ServiceTest {
@Mock
Repository repo;
@InjectMocks
Service service; // repo is injected here
@Test
void testService() {
when(repo.getData()).thenReturn("mocked");
assertEquals("mocked", service.process());
}
}
4. @Spy
The @Spy annotation in Mockito creates a partial mock, meaning it uses a real object but allows you to override certain methods. Unlike @Mock, which fakes the whole object, @Spy keeps the real behavior unless you specifically change it.
Example:
Java
@ExtendWith(MockitoExtension.class)
class ListTest {
@Spy
List<String> list = new ArrayList<>(); // real list
@Test
void testSpy() {
doReturn(100).when(list).size(); // override size()
list.add("A"); // real add() method is called
assertEquals(100, list.size());
}
}
Creating Mock Objects
Java
import static org.mockito.Mockito.*;
// Method 1: Using mock() method
List<String> mockList = mock(List.class);
// Method 2: Using @Mock annotation
@Mock
List<String> mockList;
This shows two ways to create mocks, either directly with the mock() method or using the @Mock annotation for cleaner, annotation-based setup.
Common Mockito Methods
1. when().thenReturn()
Used for stubbing method calls to return specific values.
Java
when(mockList.get(0)).thenReturn("First Element");
when(mockList.size()).thenReturn(5);
2. when().thenThrow()
Used for stubbing method calls to throw exceptions.
Java
when(mockList.get(anyInt())).thenThrow(new RuntimeException("Error"));
3. verify()
Used to verify that certain methods were called.
Java
verify(mockList).add("Element");
verify(mockList, times(2)).size();
verify(mockList, never()).clear();
4. Argument Matchers
Mockito provides argument matchers for flexible method matching.
Common Argument Matchers:
Matcher | Description |
---|
any() | Matches any object |
anyInt() | Matches any integer |
anyString() | Matches any string |
eq() | Matches equal values |
isNull() | Matches null values |
Mockito Essentials in One Simple Example
This example demonstrates how to use Mockito’s @Mock, @Spy, and @InjectMocks annotations and methods together to test a service class in isolation while controlling dependencies and partially mocking real objects.
Java
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
// Extend test with Mockito support
@ExtendWith(MockitoExtension.class)
public class ShoppingCartTest {
// Dependency mock (fake implementation)
@Mock
private PaymentService paymentService;
// Real object spy (keeps real behavior but can be stubbed)
@Spy
private List<String> items = new ArrayList<>();
// Class under test, dependencies auto-injected
@InjectMocks
private ShoppingCart cart;
@Test
void testCheckoutSuccessful() {
// Arrange - stub payment approval
when(paymentService.processPayment(100)).thenReturn(true);
// Spy allows us to use real add() but we can still verify calls
items.add("Apple");
items.add("Banana");
// Act
boolean result = cart.checkout(100);
// Assert
assertTrue(result);
verify(paymentService).processPayment(100);
verify(items, times(2)).add(anyString());
}
@Test
void testCheckoutFailsDueToPayment() {
// Arrange
when(paymentService.processPayment(200)).thenReturn(false);
items.add("Laptop");
// Act
boolean result = cart.checkout(200);
// Assert
assertFalse(result);
verify(paymentService).processPayment(200);
}
}
// ==== Production Classes ====
class ShoppingCart {
private PaymentService paymentService;
private List<String> items;
public ShoppingCart(PaymentService paymentService, List<String> items) {
this.paymentService = paymentService;
this.items = items;
}
public boolean checkout(int amount) {
if (items.isEmpty()) {
return false;
}
return paymentService.processPayment(amount);
}
}
interface PaymentService {
boolean processPayment(int amount);
}
Explaination:
- @Mock, @Spy, and @InjectMocks set up fake and partial objects for testing.
- MockitoAnnotations.openMocks(this) initializes them before each test.
- when(...).thenReturn(...) defines mock behavior.
- Call the service method to run the test logic.
- assertEquals(...) checks the result.
- verify(...) confirms expected method calls.
Best Practices
- Use @Mock annotation: It makes the code cleaner and more readable.
- Verify important interactions: Use verify() to ensure expected method calls occurred.
- Keep tests simple: Mock only what's necessary for the test.
- Use argument matchers appropriately: Don't overuse them, prefer exact values when possible.
Common Mistakes to Avoid
- Over-mocking: Mocking too many objects makes tests complex and brittle.
- Mixing mocks and real objects: Be consistent in your testing approach.
- Not verifying interactions: Missing important verification calls.
Explore
Java Basics
OOP & Interfaces
Collections
Exception Handling
Java Advanced
Practice Java