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
Scalable i18n Testing in Cypress: Semantic Assertions via i18next Integration
Sebastian Clavijo Suero demonstrates how integrating i18next into Cypress prevents test failures by asserting translation keys instead of fragile hardcoded strings.
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.
Reuse Embedded Kafka Broker Across Test Classes to Speed Up Integration Tests
Reuse embedded Kafka brokers in tests to reduce startup time by 70% and cut CI build overhead.