Explain Codes LogoExplain Codes Logo

How to capture a list of specific type with mockito

java
mockito
argument-captor
test-verification
Alex KataevbyAlex Kataev·Oct 23, 2024
TLDR

In Mockito, to capture a list of a specific type, use the ArgumentCaptor class with a wildcard ?. Here's an example with List<String>:

ArgumentCaptor<List<?>> argumentCaptor = ArgumentCaptor.forClass(List.class); verify(mockedList).someMethod(argumentCaptor.capture()); List<?> captured = argumentCaptor.getValue(); assertTrue(captured.stream().allMatch(item -> item instanceof String));

Assertions employ the instanceof to guarantee the list comprises solely String types due to type erasure.

If you're confident about the list's uniform type (bold assumption), suppress warnings to avoid the pesky linting monster:

@SuppressWarnings("unchecked") ArgumentCaptor<List<String>> captor = (ArgumentCaptor<List<String>>) (Object)ArgumentCaptor.forClass(List.class);

The "Catching" Setup

Kickstart the captor with either the @Captor annotation along with MockitoAnnotations.initMocks(this) in your setup method, or by sparking an instance of ArgumentCaptor<ArrayList<SomeType>>.

@Captor ArgumentCaptor<List<SomeType>> captor; @Before public void init() { MockitoAnnotations.initMocks(this); }

Just like catching Pokémon, capture the list in your test method verification phase:

verify(service).performAction(captor.capture()); List<SomeType> capturedList = captor.getValue(); assertThat(capturedList, hasItem(someExpectedType));

For our nerdy satisfaction, let's verify behaviors and analyze each element of the list.

Dodging Generics' Grenades

Type erasure in Java generics can throw off your Mockito game:

  • Type token: A parameterized type like ArrayList<SomeType> doesn't have a Class object, hence casting is your savior.
  • Introspection: Brace yourself to inspect individual list items to spot their types if ArgumentCaptor falls short.
  • Nested generics: Are the bane of readable tests. Use the @Captor annotation to simplify and demystify.

Swaggering with Special Cases

Catching multiple lists

Multi-list method returning octopus? Keep those ArgumentCaptors coming! And always call initMocks(this).

The Unpredictable Lists

When list order is as reliable as a flip of a coin, use Hamcrest matchers like containsInAnyOrder for verification.

The Generics Juggle

Methods with generic varargs (T... items) can be captured as a list, and their assertions made much like their list brethren.

Ironclad Test Strategy

Inspect List Properties

Not just types, keep an eye on size, order, and content of the list. No room for Trojan horses!

Tailored Matchers

For convoluted assertions, custom Argument Matchers can be your loyal passphrase to concise verification logic.

Exception Handlers

Remember to test exceptional cases. Test for exceptions when incorrect types are added to the list. Embrace the chaos.