Alexei Blue Alexei Blue - 28 days ago 16
Java Question

Mockito ArgumentCapture to doesn't recognise multiple generic types

I'm trying to use Mockito's ArgumentCapture to retrieve a generic argument used however in my method the same base type is used but with different generic arguments twice.

To simplify the example I've written a test different from my code but with the same problem:

@Captor private ArgumentCaptor<ArrayList<String>> stringl;
@Captor private ArgumentCaptor<ArrayList<Boolean>> booleanl;

@Before
public void setup()
{
MockitoAnnotations.initMocks(this);
} //setup

@Test
public void test()
{
Foo foo = mock(Foo.class);

List<String> stringList = new ArrayList<String>();
List<Boolean> booleanList = new ArrayList<Boolean>();

foo.doSomething(stringList);
foo.doSomething(booleanList);

verify(foo).doSomething(stringl.capture());
verify(foo).doSomething(booleanl.capture());
} //test

private static class Foo
{
public <T> void doSomething(List<T> list){}
}


Executing the test produces the following error:

org.mockito.exceptions.verification.TooManyActualInvocations:
foo.doSomething(<Capturing argument>);
Wanted 1 time:
-> at test(Test.java:19)
But was 2 times. Undesired invocation:
-> at test(Test.java:21)


To see what was happening I added
times(2)
to the verify methods and then inspected the argument captures. Both picked up the second invocation meaning I could never capture the first argument of type
List<String>
.

Is there a way to get ArgumentCapture to recognise different generic types for the same base type i.e. differentiate between List and List?

Cheers,
Alexei Blue

Answer

Not using the existing ArgumentCaptor class. Due to type-erasure this information is lost. I suggest you use a single captor and get the argument passed in all invocations. You can then verify that it was called the first time with List<String> and the second time with List<Boolean>. Of course you would do this by verifying the contents of the Lists.