Mocking method returning wildcards generics using mockito

I am using mockito 1.9.5. I have the following code:

public class ClassA { public List<? extends MyInterface> getMyInterfaces() { return null; } public static void testMock() { List<MyInterface> interfaces = new ArrayList<>(); ClassA classAMock = mock(ClassA.class); when(classAMock.getMyInterfaces()).thenReturn(interfaces); } 

I get a compilation error for thenReturn(interfaces) saying:

 "The method thenReturn(List<capture#1-of ? extends MyInterface>) in the type OngoingStubbing<List<capture#1-of ? extends MyInterface>> is not applicable for the arguments (List<MyInterface>)" 

However, when I use the thenAnswer mockito method, I do not get an error. Can someone tell me what is going on? Why am I getting an error when using the thenReturn method? Is there any other way to solve this problem if ClassA provided by a third party and cannot be changed?

+40
java generics mockito
Apr 11 '13 at 7:21
source share
2 answers

EDIT . Starting with Mockito 1.10.x, the generic types built into the class are now used by Mockito for deep stubs. i.e.

 public interface A<T extends Observer & Comparable<? super T>> { List<? extends B> bList(); T observer(); } B b = deep_stubbed.bList().iterator().next(); // returns a mock of B ; mockito remebers that A returns a List of B Observer o = deep_stubbed.observer(); // mockito can find that T super type is Observer Comparable<? super T> c = deep_stubbed.observer(); // or that T implements Comparable 

Mockito is struggling to get the type information that the compiler uses, but when erasing is applied, mockito cannot do anything but return mock from Object .




Original : Well, this is more of a problem with generics than with Mockito. For generics, you should read what Angelika Langer wrote on them. And for the current topic, i.e. wildcards, read this section .

But for brevity, what you could use is another Mockito syntax that will help you in your current situation:

 doReturn(interfaces).when(classAMock).getMyInterfaces(); 

Or using BDD aliases:

 willReturn(interfaces).given(classAMock).getMyInterfaces(); 

However, you can write wrappers that are more versatile. This will help future developers work with the same third-party API.




As a side note: you should not scoff at a type that you do not own, this can lead to many errors and problems. Instead, you should have a shell. DAO and repositories, for example, represent such an idea; they will mock the DAO or repository interface, but not with JDBC / JPA / hibernate. There are many blog posts about this:

+49
Apr 11 '13 at 9:16 on
source share

Another solution (albeit less readable) is to define a static method of calling when to bind the template:

 Mockito.<List<? extends MyInterface>>when(classAMock.getMyInterfaces()).thenReturn(interfaces); 
+34
Oct 01 '13 at 14:44
source share



All Articles