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

Java 使用mockito模拟使用通配符返回泛型的方法,java,generics,mockito,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 classAMoc

我用的是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);      
}
然而,当我使用mockito的
thenAnswer
方法时,我没有得到错误。谁能告诉我发生了什么事?为什么在使用
thenReturn
方法时会出现错误?
ClassA
由第三方提供且无法修改时,是否有其他方法解决此问题?

编辑:从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
或使用BDD别名:

willReturn(interfaces).given(classAMock).getMyInterfaces();
不过,您可以编写更通用友好的包装器。这将帮助未来的开发人员使用相同的第三方API


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


编辑:从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
或使用BDD别名:

willReturn(interfaces).given(classAMock).getMyInterfaces();
不过,您可以编写更通用友好的包装器。这将帮助未来的开发人员使用相同的第三方API


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

另一种解决方案(尽管可读性较差)是在绑定通配符时限定
的静态方法调用:

Mockito.<List<? extends MyInterface>>when(classAMock.getMyInterfaces()).thenReturn(interfaces);
Mockito.另一种解决方案(尽管可读性较差)是在绑定通配符时限定
的静态方法调用:

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

Mockito。在
getMyInterfaces
的returntype中不应该有通配符。这不是一个好的实践,因为那个api的客户端必须处理一个通配符,而他们对通配符一无所知。我不控制这个api。它是由第三方提供的。@SpaceTrucker我认为有一个类似于
列表的返回类型您不应该在
getMyInterfaces
的返回类型中使用通配符。这不是一个好的实践,因为那个api的客户端必须处理一个通配符,而他们对通配符一无所知。我不控制这个api。它是由第三方提供的。@SpaceTrucker我想有一个类似
列表的返回类型,也感谢您提供的有见地的链接!但是,
doReturn
语法不是类型安全的(您可以返回任何内容,而不仅仅是一个列表)。(尽管在此设置过程中仍然会出现异常,但如果您放入不同类型的列表,则不会出现异常。)@PaŭloEbermann确实,这是由于类型擦除造成的。在这种情况下,检查是在运行时完成的。另一个表单可以在编译时进行类型检查。也感谢您提供的有见地的链接!但是,
doReturn
语法不是类型安全的(您可以返回任何内容,而不仅仅是一个列表)。(尽管在此设置过程中仍然会出现异常,但如果您放入不同类型的列表,则不会出现异常。)@PaŭloEbermann确实,这是由于类型擦除造成的。在这种情况下,检查是在运行时完成的。另一个表单可以在编译时进行类型检查。可能是因为类型擦除阻止Mockito从泛型获取更多信息,所以它不知道泛型是a还是a,可能是因为类型擦除阻止Mockito从泛型获取更多信息,所以它不知道泛型是a还是a