Mockito isA(Class<T> clazz) 如何解决类型安全?



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

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

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

isA(Iterable<Integer>.class)
isA((Iterable<Integer>)Iterable.class

不要工作。

有什么建议吗?

Mockito/Hamcrest和泛型类

是的,这是Mockito/Hamcrest的一个普遍问题。通常,将isA()与泛型类一起使用会产生警告。

对于最常见的泛型类:anyList()、anyMap()anySet()anyCollection(),有预先定义的Mockito匹配器。

建议:

Mockito 2.1.0中的anyIterable()

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

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

在Eclipse中忽略

如果您只是想摆脱Eclipse中的警告。选项存在于Eclipse Indigo:之后

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

使用@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<Iterable<Integer>>() {}))))
            .thenReturn(...);

通用匹配器类:

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

以下是我所做的:

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

您可以在语句上方添加@SuppressWarnings("unchecked")。没有其他方法,但如果它让您感到困扰,您可以将强制转换移动到辅助方法。

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

Class<Iterable<Integer>> iterableIntegerClass = ?

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

interface IntegerIterable extends Iterable<Integer> {}

然后

isA(IntegerIterable.class)

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

public class IntegerArrayList extends ArrayList<Integer> implements IntegerIterable {}

嗯,好吃。。。

所以,我建议你考虑在你的方法中添加来掩盖裂缝

@SuppressWarnings("unchecked")

相关内容

  • 没有找到相关文章

最新更新