In this blog, we’ll explore what mocking is, why it's useful, and how to implement it using JUnit mock with a popular mocking framework—Mockito.
What Is Mocking?
Mocking is a technique used in unit testing to replace real objects with fake (mock) objects that simulate the behavior of real components.
For example, consider a class that depends on an external service like a database, API, or file system. Instead of invoking the actual dependency in a unit test (which makes tests slower and brittle), you can mock the dependency and define expected behavior.
This helps ensure your unit test focuses only on the logic of the class being tested, not its dependencies.
Why Use Mocks in Unit Testing?
Here are key reasons why mocking is crucial:
- Isolation: Test only the unit under consideration.
- Speed: Avoid expensive operations like API calls or database access.
- Stability: Mocks are consistent and don’t depend on external systems.
- Verification: You can verify if methods were called and with what arguments.
Introduction to Mockito
While JUnit is used for writing tests, it doesn’t have built-in support for mocking. That’s where Mockito comes in.
Mockito is the most popular mocking framework in the Java ecosystem. It works well with JUnit and allows you to create and configure mock objects with ease.
Maven Dependency
To use Mockito with JUnit 5, add the following to your pom.xml:
xml
CopyEdit
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.3.1</version>
<scope>test</scope>
</dependency>
Basic Mocking Example
Let’s say you have the following service and repository:
java
CopyEdit
public class UserRepository {
public String findNameById(int id) {
// Imagine this hits a real database
return "John Doe";
}
}
public class UserService {
private UserRepository repository;
public UserService(UserRepository repository) {
this.repository = repository;
}
public String getUppercaseUserName(int id) {
return repository.findNameById(id).toUpperCase();
}
}
Test with Mockito Mock
java
CopyEdit
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
public class UserServiceTest {
@Test
public void testGetUppercaseUserName() {
// Create mock object
UserRepository mockRepo = mock(UserRepository.class);
// Define behavior
when(mockRepo.findNameById(1)).thenReturn("jane doe");
// Inject mock into service
UserService service = new UserService(mockRepo);
// Run test
String result = service.getUppercaseUserName(1);
// Assert
assertEquals("JANE DOE", result);
// Verify interaction
verify(mockRepo).findNameById(1);
}
}
Key Mockito Functions
- mock(Class<T>): Creates a mock instance.
- when(...).thenReturn(...): Defines what the mock should return.
- verify(...): Checks if a method was called.
- doThrow(...), doNothing(): Useful for testing exception scenarios.
Using @Mock and @InjectMocks
Mockito also provides annotations to simplify mocking.
java
CopyEdit
@ExtendWith(MockitoExtension.class)
public class UserServiceTest {
@Mock
private UserRepository mockRepo;
@InjectMocks
private UserService service;
@Test
public void testGetUppercaseUserName() {
when(mockRepo.findNameById(1)).thenReturn("Jane");
String result = service.getUppercaseUserName(1);
assertEquals("JANE", result);
verify(mockRepo).findNameById(1);
}
}
This approach eliminates manual creation and injection of mock objects.
Common Mocking Scenarios
- Return different values for different inputs using when(...).thenReturn(...).
- Simulate exceptions using when(...).thenThrow(...).
- Check call counts using verify(mock, times(n)).
- Avoid real side effects such as API calls or DB writes in tests.
Best Practices
- Mock only what you own: Avoid mocking third-party classes unless necessary.
- Keep tests small and focused on a single behavior.
- Don’t overuse mocks—for integration or end-to-end testing, use real dependencies.
- Use clear naming for test methods and mocks to improve readability.
Conclusion
Mocking in unit tests is a critical skill for any Java developer. With JUnit and Mockito, you can write fast, reliable, and maintainable tests that validate your application logic in isolation.
Whether you're testing a simple method or a complex service with multiple dependencies, mocking gives you control and confidence in your codebase. It’s not just about avoiding external dependencies—it’s about writing robust tests that catch real bugs.
Read more- https://keploy.io/blog/community/simplifying-junit-test-stubs-and-mocking