Why Mocking Java Collections with Mockito is Problematic
These articles are AI-generated summaries. Please check the original sources for full details.
Why We Should Not Mock Collections With Mockito
Mockito, a popular testing library in the Java ecosystem, is often misused by mocking Java collections such as List, Set, or Map, which can lead to brittle tests and unrealistic behavior. According to Neetika Khandelwal, mocking collections is rarely a good idea and can result in test failures on modern Java versions due to stricter JVM constraints.
Why This Matters
Mocking collections can increase complexity without providing meaningful isolation, as Java collections are part of the core JDK, deterministic, lightweight, and extensively tested. This practice can lead to tests that pass even though they do not reflect real runtime behavior, ultimately reducing confidence in the tests. For instance, on Java 21 and later, Mockito may throw an exception when attempting to mock a List, highlighting the potential issues with this approach.
Key Insights
- Mockito cannot mock certain core JDK types, such as List, on newer Java versions: Java 21 and later have stricter JVM rules around runtime instrumentation of core JDK types.
- Using real collections in tests tends to expose design issues and encourages cleaner APIs: by avoiding mocking collections, developers can write more resilient and maintainable code.
- Good unit tests should protect refactoring, not resist it: tests should focus on observable behavior rather than implementation details.
Working Example
public class UserService {
private final List<String> users;
public UserService(List<String> users) {
this.users = users;
}
public boolean hasUsers() {
return !users.isEmpty();
}
public String getFirstUser() {
if (users.isEmpty()) {
return null;
}
return users.get(0);
}
}
@Test
void givenList_whenRealCollectionIsUsed_thenShouldReturnFirstUser() {
List<String> users = new ArrayList<>();
users.add("Joey");
UserService userService = new UserService(users);
assertTrue(userService.hasUsers());
assertEquals("Joey", userService.getFirstUser());
}
Practical Applications
- Use Case: Using real collections in tests, such as ArrayList, to verify the behavior of a UserService class.
- Pitfall: Mocking collections with Mockito, which can lead to brittle tests and unrealistic behavior, and potentially cause test failures on newer Java versions.
References:
Continue reading
Next article
Clearing Console Screen in Java
Related Content
Optimizing Cypress E2E Tests: Testing Real Email Flows Without Infrastructure
Eliminate Docker and MailHog from Cypress E2E tests using ZeroDrop for isolated, real email flow verification without mocking.
How to Mock Amazon SQS in Unit Tests with Dependency Injection and Mockito
A comprehensive guide to mocking Amazon SQS in unit tests using dependency injection and Mockito for fast, deterministic, and credential-free testing.
Beyond the Red Icon: Engineering High-Signal Evidence for Browser Testing
Shift focus from test execution speed to evidence quality to prevent unresolved events from blocking production releases in CI/CD pipelines.