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

Mik*_*ike 28 java junit mockito java-5

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

when(client.runTask(anyString(), anyString(), isA(Iterable.class)).thenReturn(...)
Run Code Online (Sandbox Code Playgroud)

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

isA(Iterable<Integer>.class)
isA((Iterable<Integer>)Iterable.class
Run Code Online (Sandbox Code Playgroud)

不工作.

有什么建议?

Are*_*rff 28

Mockito/Hamcrest和泛型课程

是的,这是Mockito/Hamcrest的普遍问题.通常使用isA()泛型类会产生警告.

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

建议:

Mockito 2.1.0中的anyIterable()

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

when(client.runTask(anyString(), anyString(), anyIterable()).thenReturn(...)
Run Code Online (Sandbox Code Playgroud)

在Eclipse中忽略

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

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

使用@SuppressWarnings快速修复

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

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

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

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

  • 语法不太漂亮,可能会让一些人感到困惑.
  • 您对提供TypeToken该类的库有额外的依赖性.在这里,我使用了GuavaTypeToken类.TypeToken在Gson和GenericTypeJAX-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(...);
Run Code Online (Sandbox Code Playgroud)

通用匹配器类:

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());
    }
}
Run Code Online (Sandbox Code Playgroud)


Dan*_*den 7

这是我做的:

// 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
Run Code Online (Sandbox Code Playgroud)


Gar*_*all 4

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