Explain Codes LogoExplain Codes Logo

Mockito: List Matchers with generics

java
mockito
generics
argument-matchers
Nikita BarsukovbyNikita Barsukov·Nov 24, 2024
TLDR

To test generic lists with Mockito use any() with explicit type casting. This secures the generic type at compile time, crucial for stubbing or verifying methods that accept generic lists as parameters.

when(mockList.addAll(any())).thenReturn(true); verify(mockList).addAll((List<String>) any()); // Who would've thought - casting in Java! :)

The cast (List<String>) notifies Mockito you're manipulating a List of Strings, thus ensuring the method calls are type-safe.

Mockito and Generics: Combining powers

When Generics Met Matchers

Utilize ArgumentMatchers.any() method when working with Java 8 and above. It's more succinct and leverages type inference:

when(mockList.addAll(ArgumentMatchers.<String>any())).thenReturn(true); // Did you infer that, Sherlock? :) verify(mockList).addAll(ArgumentMatchers.<String>anyList());
BONUS: generic types are inferred and remain **strongly typed** without verbose casting. Win-win!

Handing Overload with Grace

Overloaded methods can cause hiccups with Mockito. Put those worries to rest by using generic type matchers to slice through ambiguity:

// When there's more on the menu... verify(mockedList).add(ArgumentMatchers.<MyClass>any());

Back to the Future (or Past)

In Java 7 and below, any() doesn't infer types. Use Matchers.anyListOf(Class<T> clazz) to maintain the peace (and functionality):

when(mockList.addAll(Matchers.<String>anyListOf(String.class))).thenReturn(true); verify(mockList).addAll(Matchers.<String>anyListOf(String.class)); // Smells like legacy code

In Raw We Trust (not really)

Avoid raw types to guard type checks. But when you must deal with them, arm yourself with the correct casting spells:

when(mockList.addAll((List) any())).thenReturn(true); // The Wild West of Generics verify(mockList).addAll((List)Matchers.anyList());

ArgumentMatchers: The Swiss Knife

When wrestling with method parameters, ArgumentMatchers API is your lifesaver providing a pragmatic way to articulate the intended type and simplify your life using static imports:

import static org.mockito.ArgumentMatchers.*; // Now you see me... when(mockList.addAll(anyList())).thenReturn(true); verify(mockList).addAll(anyList()); // Now you don't

Diving deeper: Advanced Mocking Strategies

Pinpoint Matching with Nested Generics

For as complex as it gets scenarios, say nested generics, go for the Matchers API with fully blown explicit generics:

when(mockSomeObject.someMethod(Matchers.<List<List<String>>>any())).thenReturn(someResult); // You had me at nested generics!

Capturing the Buttery Goodness with ArgumentCaptor

Get the actual values passed to your mock using ArgumentCaptor, adding another tool in your testing kit:

ArgumentCaptor<List<String>> captor = ArgumentCaptor.forClass((Class) List.class); // Captor, I choose you! verify(mockList).addAll(captor.capture()); assertTrue(captor.getValue().containsAll(expectedList)); // Mind reader in action