Mockito:バインドされたワイルドカードで型を返すスタブメソッド


135

このコードを考えてみましょう:

public class DummyClass {
    public List<? extends Number> dummyMethod() {
        return new ArrayList<Integer>();
    }
}
public class DummyClassTest {
    public void testMockitoWithGenerics() {
        DummyClass dummyClass = Mockito.mock(DummyClass.class);
        List<? extends Number> someList = new ArrayList<Integer>();
        Mockito.when(dummyClass.dummyMethod()).thenReturn(someList); //Compiler complains about this
    }
}

コンパイラは、の動作をスタブ化しようとしている行について文句を言いdummyMethod()ます。ワイルドカードがバインドされた型を返すメソッドをスタブする方法についてのポインタはありますか?


コードスニペットを更新してジェネリック型を表示できますか?
ミルハウス'28

1
できました。preタグとcodeタグを削除する必要があり、それらは取り除かれていました<?型宣言からNumber>を拡張します。
Shikhar Mishra、2011

回答:


190

この目的で、タイプセーフでないメソッドdoReturnを使用することもできます。

@Test
public void testMockitoWithGenerics()
{
    DummyClass dummyClass = Mockito.mock(DummyClass.class);
    List<? extends Number> someList = new ArrayList<Integer>();

    Mockito.doReturn(someList).when(dummyClass).dummyMethod();

    Assert.assertEquals(someList, dummyClass.dummyMethod());
}

Mockitoのグーグルグループで議論されたように。

これはより単純ですがthenAnswer、タイプセーフではないことに注意してください。タイプセーフについて心配している場合は、millhouseの答えは正しいです。

さらなる詳細

明確にするために、ここに観察されたコンパイラエラーがあります、

The method thenReturn(List<capture#1-of ? extends Number>) in the type OngoingStubbing<List<capture#1-of ? extends Number>> is not applicable for the arguments (List<capture#2-of ? extends Number>)

コンパイラがwhen呼び出し中に最初のワイルドカードタイプを割り当てたため、呼び出しの2番目のワイルドカードタイプがthenReturn同じであることを確認できないと思います。

それは次のようになりthenAnswerながら、それはワイルドカードタイプを受け入れるために、この問題に実行されませんthenReturn捕獲しなければならない非ワイルドカード型を取ります。MockitoのOngoingStubbingから、

OngoingStubbing<T> thenAnswer(Answer<?> answer);
OngoingStubbing<T> thenReturn(T value);

これは部分的に私にも役立ちます...しかし、返すと予想されるリストが空でない場合はどうなりますか?
ttati

空のリストを作成する代わりに、次のこともできます。List <Number> someList = new ArrayList <Integer>(); someList.add(aNumber);
ttati

32

someListいくつかの既知の値をロードできるようにしたいと思います。Answer<T>すべてをタイプセーフに保つためにテンプレート化されたヘルパーメソッドと一緒に使用するアプローチは次のとおりです。

@Test
public void testMockitoWithGenericsUsingAnswer()
{
    DummyClass dummyClass =  Mockito.mock(DummyClass.class);

    Answer<List<Integer>> answer = setupDummyListAnswer(77, 88, 99);
    Mockito.when(dummyClass.dummyMethod()).thenAnswer(answer);

    ...
}

private <N extends Number> Answer<List<N>> setupDummyListAnswer(N... values) {
    final List<N> someList = new ArrayList<N>();

    someList.addAll(Arrays.asList(values));

    Answer<List<N>> answer = new Answer<List<N>>() {
        public List<N> answer(InvocationOnMock invocation) throws Throwable {
            return someList;
        }   
    };
    return answer;
}

17

私は昨日同じことを思いつきました。@ nondescript1と@millhouseからの回答はどちらも、回避策を見つけるのに役立ちました。私はかなり私のエラーが原因ではなかったので、私はそれが少しより汎用的な作られたことを除いて、@millhouseと同じコードを使用しましたjava.util.Listが、com.google.common.base.Optional。したがって、私の小さなヘルパーメソッドはT、次のものだけでなく、あらゆるタイプを許可しますList<T>

public static <T> Answer<T> createAnswer(final T value) {
    Answer<T> dummy = new Answer<T>() {
        @Override
        public T answer(InvocationOnMock invocation) throws Throwable {
            return value;
        }
    };
    return dummy;
}

このヘルパーメソッドを使用すると、次のように記述できます。

Mockito.when(dummyClass.dummyMethod()).thenAnswer(createAnswer(someList));

これは問題なくコンパイルされ、thenReturn(...)メソッドと同じことを行います。

Javaコンパイラーが発行するエラーがコンパイラーのバグなのか、コードが本当に間違っているのか誰かが知っていますか?


これは単純明快でシンプルで、私が知る限りでは正しいようです。Mockitoがこれに似たものを提供しない理由がわかりません。
vacao 2015年

14
Java 8では短縮できます:Mockito.when(dummyClass.dummyMethod()).thenAnswer(x -> someList)、つまりユーティリティメソッドは必要ありません
fikovnik

1
@fikovnik「thenAnswer」というすばらしい発見です。
ボルジャブ

5

私はfikovnikのコメントをここで回答に変えて、Java 8+を使用する最もエレガントなソリューションであると思うので、より見やすくします。

Mockitoのドキュメントでは、使用することをお勧めしますdoReturn()(受け入れ答えで提案されているように)最後の手段としてのみ。

代わりに、質問で説明されているコンパイラエラーを回避するために、推奨されるMockito when()アプローチをthenAnswer()(ヘルパーメソッドの代わりに)およびラムダで使用できます。

Mockito.when(mockedClass.mockedMethod()).thenAnswer(x -> resultList)

コンパイル時エラーは発生しませんが、エントリのあるリストを渡しても、返されるリストは空です。
Venkatesh Kolla-user2742897

0

Marek Radonskyによって提案された実用的な方法は機能しますが、(IMHOの奇妙に見える)ラムダ式fikovnikが提案することさえ必要としない他のオプションもあります:

この回答類似した質問のショーに、あなたはまた、次のように使用することができます。

BDDMockito.willReturn(someList).given(dummyClass).dummyMethod();
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.