Mockito isA(Class clazz)如何解决类型安全问题?

在我的测试中我有以下几行:

when(client.runTask(anyString(), anyString(), isA(Iterable.class)).thenReturn(...) 

isA(Iterable.class)产生警告,它需要未经检查的转换以符合Iterable 。 这是什么语法?

 isA(Iterable.class) isA((Iterable)Iterable.class 

不工作。

有什么建议么?

Mockito / Hamcrest和generics课程

是的,这是Mockito / Hamcrest的普遍问题。 通常使用带有generics类的isA()会产生警告。

对于最常见的generics类,存在预定的Mockito匹配器: anyList() , anyMap()anySet()anyCollection()

建议:

Mockito 2.1.0中的anyIterable()

Mockito 2.1.0添加了一个新的anyIterable()方法来匹配Iterables:

 when(client.runTask(anyString(), anyString(), anyIterable()).thenReturn(...) 

在Eclipse中忽略

如果你只想摆脱Eclipse中的警告。 自Eclipse Indigo以来存在选项:

窗口>首选项> Java>编译器>错误/警告>通用类型>忽略不可避免的generics类型问题

使用@SuppressWarnings快速修复

如果您只遇到一次问题,我建议您这样做。 我个人不记得曾经需要一个isA(Iterable.class)

正如Daniel Pryden所说,您可以将@SuppressWarnings限制为局部变量或辅助方法。

使用带有TypeToken的通用isA()匹配器

这样可以很好地解决问题。 但它有两个缺点:

  • 语法不太漂亮,可能会让一些人感到困惑。
  • 您对提供TypeToken类的库有额外的依赖性。 在这里,我使用了Guava的TypeToken类 。 在Gson中还有一个TypeToken类,在JAX-RS中也有一个GenericType

使用通用匹配器:

 import static com.arendvr.matchers.InstanceOfGeneric.isA; import static org.mockito.ArgumentMatchers.argThat; // ... when(client.runTask(anyString(), anyString(), argThat(isA(new TypeToken>() {})))) .thenReturn(...); 

通用匹配器类:

 package com.arendvr.matchers; import com.google.common.reflect.TypeToken; import org.mockito.ArgumentMatcher; public class InstanceOfGeneric implements ArgumentMatcher { private final TypeToken typeToken; private InstanceOfGeneric(TypeToken typeToken) { this.typeToken = typeToken; } public static  InstanceOfGeneric isA(TypeToken typeToken) { return new InstanceOfGeneric<>(typeToken); } @Override public boolean matches(Object item) { return item != null && typeToken.getRawType().isAssignableFrom(item.getClass()); } } 

这是我做的:

 // Cast from Class to Class> via the raw type. // This is provably safe due to erasure, but will generate an unchecked warning // nonetheless, which we suppress. @SuppressWarnings("unchecked") Class> klass = (Class>) (Class) Iterable.class; // later isA(klass) // <- now this is typesafe 

您可以在语句上方添加@SuppressWarnings("unchecked") 。 没有其他办法,但如果它困扰你,你可以将演员阵容移动到辅助方法。

没有办法做到这一点。 为简化起见,您无法在不发出警告的情况下初始化此变量:

 Class> iterableIntegerClass = ? 

一种解决方案可能是使用伪typedef反模式 ,您创建并使用IntegerIterable接口

 interface IntegerIterable extends Iterable {} 

然后

 isA(IntegerIterable.class) 

将不再发出警告。 但是你必须扩展实现Iterable的类,让它们实现IntegerIterable :)例如:

 public class IntegerArrayList extends ArrayList implements IntegerIterable {} 

嗯好吃……

所以,我会鼓励你考虑通过添加到你的方法来解决问题:

 @SuppressWarnings("unchecked")