32

私のテストでは、次の行があります。

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

isA(Iterable.class)に準拠するには未チェックの変換が必要であるという警告を生成しますIterable<Integer>。そのための構文は何ですか?

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

動作しない。

助言がありますか?

4

4 に答える 4

31

Mockito/Hamcrestおよびジェネリッククラス

はい、これはMockito/Hamcrestの一般的な問題です。通常isA()、ジェネリッククラスで使用すると、警告が発生します。

最も一般的な汎用クラスには、事前に定義されたMockitoマッチャーがあります:anyList()、、、および。anyMap()anySet()anyCollection()

提案:

Mockito 2.1.0のanyIterable()

Mockito 2.1.0は、Iterablesを照合するための新しいanyIterable()メソッドを追加しました。

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

Eclipseでは無視する

Eclipseで警告を取り除きたいだけの場合。Eclipse Indigo以降にオプションが存在します:

ウィンドウ>設定>Java>コンパイラ>エラー/警告>ジェネリック型>避けられないジェネリック型の問題を無視する

@SuppressWarningsによるクイックフィックス

問題が1回だけ発生する場合は、これを行うことをお勧めします。私は個人的にこれまでにが必要だったことを覚えていませんisA(Iterable.class)

Daniel Prydenが言うように、を@SuppressWarningsローカル変数またはヘルパーメソッドに制限することができます。

TypeTokenで汎用isA()マッチャーを使用する

これは問題を永久に解決します。ただし、2つの欠点があります。

  • 構文はあまりきれいではなく、一部の人を混乱させる可能性があります。
  • TypeTokenクラスを提供するライブラリへの追加の依存関係があります。ここでは、GuavaのTypeTokenクラスを使用しました。TypeTokenGsonと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(...);

ジェネリックマッチャークラス:

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());
    }
}
于 2012-08-18T16:30:29.133 に答える
8

これが私がすることです:

// 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
于 2012-08-17T21:07:33.910 に答える
4

@SuppressWarnings("unchecked")ステートメントの上に追加できます。他に方法はありませんが、気になる場合は、キャストをヘルパー メソッドに移動できます。

于 2012-08-17T19:55:39.563 に答える
2

これを行う方法はありません。簡単にするために、警告なしでこの変数を初期化することはできません:

Class<Iterable<Integer>> iterableIntegerClass = ?

1 つの解決策は、疑似 typedef アンチパターンIntegerIterableを使用することです。インターフェイスを作成して使用します。

interface IntegerIterable extends Iterable<Integer> {}

それから

isA(IntegerIterable.class)

警告を生成しなくなります。Iterableただし、実装できるようにするには、実装するクラスを拡張する必要がありますIntegerIterable:)例:

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

うーん美味しい…

したがって、メソッドに追加して、亀裂を紙で覆うことを検討することをお勧めします。

@SuppressWarnings("unchecked")
于 2012-08-17T21:09:05.233 に答える