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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12012249/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 07:16:37  来源:igfitidea点击:

Mockito isA(Class<T> clazz) How to resolve type safety?

javajunitmockitojava-5

提问by Mike

in my test I have the following line:

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

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

isA(Iterable.class)produces warning that it needs unchecked conversion to conform to Iterable<Integer>. What is syntax for that?

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

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

do not work.

不工作。

Any suggestions?

有什么建议?

回答by Arend v. Reinersdorff

Mockito/Hamcrest and generic classes

Mockito/Hamcrest 和泛型类

Yes, this is a general problem with Mockito/Hamcrest. Generally using isA()with generic classes produces a warning.

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

There are predifined Mockito matchers for the most common generic classes: anyList(), anyMap(), anySet()and anyCollection().

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

Suggestions:

建议:

anyIterable() in Mockito 2.1.0

Mockito 2.1.0 中的 anyIterable()

Mockito 2.1.0 added a new anyIterable()method for matching Iterables:

Mockito 2.1.0 添加了一个新的anyIterable()方法来匹配可迭代对象

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

Ignore in Eclipse

在 Eclipse 中忽略

If you just want to get rid of the warning in Eclipse. Option exists since Eclipse Indigo:

如果您只是想摆脱 Eclipse 中的警告。选项自Eclipse Indigo起就存在:

Window > Preferences > Java > Compiler > Errors/Warnings > Generic types > Ignore unavoidable generic type problems

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

Quick Fix with @SuppressWarnings

使用@SuppressWarnings 快速修复

I suggest you do this if you have the problem only once. I personally don't remember ever needing an isA(Iterable.class).

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

As Daniel Pryden says, you can limit the @SuppressWarningsto a local variable or a helper method.

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

Use a generic isA() matcher with TypeToken

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

This solves the problem for good. But it has two disadvantages:

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

  • The syntax is not too pretty and might confuse some people.
  • You have an additional dependency on the library providing the TypeTokenclass. Here I used the TypeToken class from Guava. There's also a TypeTokenclass in Gson and a GenericTypein JAX-RS.
  • 语法不太漂亮,可能会让一些人感到困惑。
  • 您对提供TypeToken类的库有额外的依赖。这里我使用了来自 GuavaTypeToken 类TypeToken在 Gson 中还有一个类,GenericType在 JAX-RS 中也有一个类。

Using the generic matcher:

使用通用匹配器:

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

Generic matcher class:

通用匹配器类:

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

回答by Daniel Pryden

Here's what I do:

这是我所做的:

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

回答by Garrett Hall

You can add @SuppressWarnings("unchecked")above the statement. No other way but if it bothers you, you can move the cast to a helper method.

您可以@SuppressWarnings("unchecked")在语句上方添加。别无他法,但如果它打扰您,您可以将强制转换移动到辅助方法。

回答by gontard

There is no way to do this. To simplify, you can't initialize this variable without warning :

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

Class<Iterable<Integer>> iterableIntegerClass = ?

One solution might be to use the pseudo-typedef antipattern, ,you create and use an IntegerIterableinterface

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

interface IntegerIterable extends Iterable<Integer> {}

then

然后

isA(IntegerIterable.class)

will no more produce warning. But you will have to extend the class implementing Iterableto let them implements IntegerIterable:) For example :

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

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

Mmm tasty...

嗯好吃...

So, i will sugest you to consider to just paper over the cracks by adding to your method :

所以,我会建议你考虑通过添加到你的方法来掩盖裂缝:

@SuppressWarnings("unchecked")