How to capture a list of specific type with mockito How to capture a list of specific type with mockito java java

How to capture a list of specific type with mockito


The nested generics-problem can be avoided with the @Captor annotation:

public class Test{    @Mock    private Service service;    @Captor    private ArgumentCaptor<ArrayList<SomeType>> captor;    @Before    public void init(){        MockitoAnnotations.initMocks(this);    }    @Test     public void shouldDoStuffWithListValues() {        //...        verify(service).doStuff(captor.capture()));    }}


Yeah, this is a general generics problem, not mockito-specific.

There is no class object for ArrayList<SomeType>, and thus you can't type-safely pass such an object to a method requiring a Class<ArrayList<SomeType>>.

You can cast the object to the right type:

Class<ArrayList<SomeType>> listClass =              (Class<ArrayList<SomeType>>)(Class)ArrayList.class;ArgumentCaptor<ArrayList<SomeType>> argument = ArgumentCaptor.forClass(listClass);

This will give some warnings about unsafe casts, and of course your ArgumentCaptor can't really differentiate between ArrayList<SomeType> and ArrayList<AnotherType> without maybe inspecting the elements.

(As mentioned in the other answer, while this is a general generics problem, there is a Mockito-specific solution for the type-safety problem with the @Captor annotation. It still can't distinguish between an ArrayList<SomeType> and an ArrayList<OtherType>.)

Edit:

Take also a look at tenshi's comment. You can change the original code to this simplified version:

final ArgumentCaptor<List<SomeType>> listCaptor        = ArgumentCaptor.forClass((Class) List.class);


If you're not afraid of old java-style (non type safe generic) semantics, this also works and is simple'ish:

ArgumentCaptor<List> argument = ArgumentCaptor.forClass(List.class);verify(subject.method(argument.capture()); // run your codeList<SomeType> list = argument.getValue(); // first captured List, etc.