0

ジェネリックメソッドをテストするためにmockitoを使用しています。しかし、junit-test を実行すると ClassCastException が発生します。

テスト中のメソッドは次のようになります。

public ExampleClass {
    public <E> E randomObject(List<E> list) {
            E e = list.get(0);
            return e;
    }
}

モックは次のようになります。

ExampleClass exampleMock = mock(ExampleClass.class);
List listMock = mock(List.class);
when(exampleMock.randomObject(Matchers<List<String>any())).thenReturn("Hello");
when(exampleMock.randomObject(Matchers.List<Integer>any())).thenReturn(20);

Exception はwhen-methodの 2 番目の定義で表示されます。このメソッドは、変更できない 1 つのタイプのみを受け入れているようです。しかし、なぜそうなのですか?プレーン Java で 2 つの異なる型を持つジェネリック メソッドを使用すると、例外は表示されません。

誰か助けてくれませんか?

4

1 に答える 1

2

tl;dr

コードを複数のテスト メソッドに分割します。thenReturnまたは、 API をチェーンします。

長い話

型消去を使用して実装された Java ジェネリックをおそらく認識しているように、コードに表示されるほとんどのジェネリックは、コンパイルされたバイトコードではなく、ソース コードにのみ存在することを意味します。

たとえば、次の署名はこちら

<E> E randomObject(List<E> list)

にコンパイルされます

Object randomObject(List list)

それが、mockito が見る署名です。これは matchers についても同じです:

when(exampleMock.randomObject(Matchers.<List<String>>any())).thenReturn("Hello");
when(exampleMock.randomObject(Matchers.<List<Integer>>any())).thenReturn(20);

になる

when(exampleMock.randomObject(Matchers.any())).thenReturn("Hello");
when(exampleMock.randomObject(Matchers.any())).thenReturn(20);

Mockito は、同じ matcherを使用した同じ呼び出しであることを発見しました。コードは 2 つの異なるスタブのように読み取られますが、mockito はそれを認識しておらず、開発者がこの最初のスタブをオーバーライドしたいと考えているとしか考えられません。

この mockito の動作は、既定のスタブが一部の@Beforeメソッドで宣言され、そのスタブを一部のメソッドでオーバーライドする必要があるシナリオで必要@Testです。

この場合、コードを分割するか、より複雑なシナリオの一部である場合は、スタブでチェーン API を使用する必要があります。

when(exampleMock.randomObject(Matchers.anyList()))
       .thenReturn("Hello")
       .thenReturn(20);

_matcher が、anyList()よりコンパイル時間に適したものに変更されたことに注意してください。

テストには で注釈を付けることができます@SuppressWarnings("unchecked")

于 2015-03-01T23:33:32.920 に答える