使用mockito模拟使用通配符返回泛型的方法

时间:2013-04-11 07:21:08

标签: java generics mockito

我正在使用mockito 1.9.5。 我有以下代码:

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);      
}

我收到thenReturn(interfaces)说的编译错误:

"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>)"

但是,当我使用mockito的thenAnswer方法时,我没有收到错误。谁能告诉我发生了什么事?使用thenReturn方法时,为什么会出现错误? 当ClassA由第三方提供且无法修改时,还有其他方法可以解决此问题吗?

2 个答案:

答案 0 :(得分:56)

编辑:从Mockito 1.10.x开始,Mockito现在使用嵌入在类中的泛型类型来存储深层存根。即。

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尽力获取编译器嵌入的类型信息,但是当擦除适用时,mockito除了返回Object的模拟外无法做任何事情。


原创:对于仿制品来说,这比使用Mockito更具问题。对于泛型,您应该阅读 Angelika Langer 在其上写的内容。对于当前主题,即通配符,请阅读此section

但简而言之,您可以使用的是Mockito的其他语法来帮助您了解当前的情况:

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

或使用BDD别名:

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

然而,您可以编写更通用友好的包装器。这将有助于未来的开发人员使用相同的第三方API。


作为旁注:你不应该嘲笑你不拥有的类型,它可能会导致许多错误和问题。相反,你应该有一些包装。例如,DAO和存储库代表了这样的想法,一个将模拟DAO或存储库接口,而不是JDBC / JPA / hibernate的东西。有很多博客文章:

答案 1 :(得分:45)

另一个解决方案(虽然不太可读)是限定when的静态方法调用来绑定通配符:

Mockito.<List<? extends MyInterface>>when(classAMock.getMyInterfaces()).thenReturn(interfaces);