I am trying to mock the ExecutorService but it is constantly giving compile error. The code that I am trying is the following:
ExecutorService executorService = mock(ExecutorService.class);
Future<A> mockedFuture = mock(Future.class);
List<Future<A>> list = Lists.newArrayList(mockedFuture);
when(executorService.invokeAll(any())).thenReturn(list);
When I compile this, it returns the following error:
error: no suitable method found for thenReturn(List<Future<A>>)
[javac] when(executorService.invokeAll(any())).thenReturn(futureList);
[javac] ^
[javac] method OngoingStubbing.thenReturn(List<Future<Object>>) is not applicable
[javac] (argument mismatch; List<Future<A>> cannot be converted to List<Future<Object>>)
[javac] method OngoingStubbing.thenReturn(List<Future<Object>>,List<Future<Object>>...) is not applicable
[javac] (argument mismatch; List<Future<A>> cannot be converted to List<Future<Object>>)
any idea?
Here Mockito.any()
returns a type inferred by the target of the invocation, that is executorService.invokeAll()
. But executorService.invokeAll()
doesn't declare a more specific type either as it also relies on the target inference : Mockito.when(...)
.
The type returned by any()
depends on the type returned by invokeAll()
that depends on the type returned by when()
.
But neither invokeAll()
nor when()
specifies the A
type in the generic collection.
So the generic T
type of the invokeAll()
method defined as :
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
will be seen by the compiler as Object
such as :
<Object> List<Future<Object>> invokeAll(Collection<? extends Callable<Object>> tasks)
And so any()
will return a Collection<? extends Callable<Object>>
Collection<? extends Callable<Object>>
type.
In these conditions, thenReturn()
that doesn't return a List<Future<Object>>
but a List<Future<A>>
declared type cannot compile :
argument mismatch; List<Future<A>> cannot be converted to List<Future<Object>>)
To solve your issue, you need to do an unchecked cast on Mockito.any()
(but you know that it will work):
Mockito.when(executorService.invokeAll((Collection<Callable<A>>)Mockito.any())).thenReturn(list);
Or as alternative, solve the target inference by setting explicitly the return of Mockito.any()
in a variable :
Collection<Callable<A>> any = Mockito.any();
Mockito.when(executorService.invokeAll(any)).thenReturn(list);
You should have more success with:
ExecutorService executorService = mock(ExecutorService.class);
Future<Object> mockedFuture = mock(Future.class);
List<Future<Object>> list = Lists.newArrayList(mockedFuture);
when(executorService.invokeAll(any())).thenReturn(list);
There's a clue for this the error message:
argument mismatch; List<Future<A>> cannot be converted to List<Future<Object>>
That's because with Java generics, List<Future<A>
is not a List<Future<Object>>
(nor is Future<A>
a Future<Object>
).
There are many good explanations for why this is the case, have a look on SO for Java contravariance.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.