伊萨的Mockito(类 clazz所)如何解决类型安全?(Mockito isA(Class

2019-06-27 03:31发布

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

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

isA(Iterable.class)产生警告,它需要转换选中以符合Iterable<Integer> 。 什么是语法是什么?

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

不工作。

有什么建议?

Answer 1:

的Mockito / Hamcrest和泛型类

是的,这是的Mockito / Hamcrest一个普遍的问题。 一般采用isA()与泛型类产生一个警告。

有predifined匹配器的Mockito为最常用的通用类: anyList() , anyMap() anySet()anyCollection()

建议:

anyIterable()在2.1.0的Mockito

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

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

忽略在Eclipse

如果你只是想摆脱在Eclipse的警告。 因为选项存在的Eclipse靛蓝 :

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

快速修复与@SuppressWarnings

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

正如丹尼尔Pryden说,你可以限制@SuppressWarnings局部变量或辅助方法。

使用带有TypeToken通用ISA()匹配

这解决了这个问题为好。 但它有两个缺点:

  • 语法是不是太漂亮,可能会混淆一些人。
  • 您对库提供一个额外的依赖TypeToken类。 这里我用了TypeToken类番石榴 。 还有一个TypeToken在GSON类和GenericType在JAX-RS。

使用通用的匹配:

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


Answer 2:

这是我做的:

// 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


Answer 3:

您可以添加@SuppressWarnings("unchecked")上面的语句。 没有别的办法,但如果你烦恼,你可以移动要转换成一个辅助方法。



Answer 4:

有没有办法做到这一点。 为了简化,你不能没有警告初始化这个变量:

Class<Iterable<Integer>> iterableIntegerClass = ?

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

interface IntegerIterable extends Iterable<Integer> {}

然后

isA(IntegerIterable.class)

将不再产生报警。 但是,你将不得不扩展类实现Iterable让他们实现IntegerIterable :)例如:

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

嗯美味...

所以,我会sugest您通过添加到您的方法来考虑刚过裂缝纸:

@SuppressWarnings("unchecked")


文章来源: Mockito isA(Class clazz) How to resolve type safety?