web-dev-qa-db-ja.com

Mockitoを使用してジェネリックパラメーターでクラスをモックする

ジェネリックパラメーターでクラスをモックするクリーンな方法はありますか? Foo<T>を期待するメソッドに渡す必要があるクラスFoo<Bar>をモック化する必要があるとします。次のことが簡単にできます。

Foo mockFoo = mock(Foo.class);
when(mockFoo.getValue).thenReturn(new Bar());

getValue()がジェネリック型Tを返すと仮定します。しかし、後でFoo<Bar>を期待するメソッドに渡すと、子猫が発生します。これを行う唯一の手段はキャストですか?

241
Tim Clemons

あなたはそれをキャストする必要があると思いますが、それはそれほど悪くないはずです:

Foo<Bar> mockFoo = (Foo<Bar>) mock(Foo.class);
when(mockFoo.getValue).thenReturn(new Bar());
238
John Paulett

これを回避するもう1つの方法は、代わりに@Mock注釈を使用することです。すべての場合に機能するわけではありませんが、よりセクシーに見えます:)

以下に例を示します。

@RunWith(MockitoJUnitRunner.class)
public class FooTests {

    @Mock
    public Foo<Bar> fooMock;

    @Test
    public void testFoo() {
        when(fooMock.getValue()).thenReturn(new Bar());
    }
}

MockitoJUnitRunner は、 @Mock アノテーションが付けられたフィールドを初期化します。

241
Marek Kirejczyk

指定したいジェネリック型を満たす中間クラス/インターフェースをいつでも作成できます。たとえば、Fooがインターフェイスである場合、テストクラスに次のインターフェイスを作成できます。

private interface FooBar extends Foo<Bar>
{
}

Fooが非最終クラスである状況では、次のコードでクラスを拡張し、同じことを行うことができます。

public class FooBar extends Foo<Bar>
{
}

次に、次のコードで上記の例を使用できます。

Foo<Bar> mockFoo = mock(FooBar.class);
when(mockFoo.getValue()).thenReturn(new Bar());
30
dsingleton

テストユーティリティメソッドを作成します。複数回必要な場合に特に便利です。

@Test
public void testMyTest() {
    // ...
    Foo<Bar> mockFooBar = mockFoo();
    when(mockFooBar.getValue).thenReturn(new Bar());

    Foo<Baz> mockFooBaz = mockFoo();
    when(mockFooBaz.getValue).thenReturn(new Baz());

    Foo<Qux> mockFooQux = mockFoo();
    when(mockFooQux.getValue).thenReturn(new Qux());
    // ...
}

@SuppressWarnings("unchecked") // still needed :( but just once :)
private <T> Foo<T> mockFoo() {
    return mock(Foo.class);
}
12
acdcjunior

他の誤って抑制された警告を見落とす可能性があるため、クラスまたはメソッドで警告を抑制するべきではないことに同意します。しかし、私見では、1行のコードのみに影響する警告を抑制することは絶対に合理的です。

@SuppressWarnings("unchecked")
Foo<Bar> mockFoo = mock(Foo.class);
3
Tobias Uhmann

興味深いケースがあります:メソッドはジェネリックコレクションを受け取り、同じベースタイプのジェネリックコレクションを返します。例えば:

Collection<? extends Assertion> map(Collection<? extends Assertion> assertions);

このメソッドは、Mockito anyCollectionOfマッチャーとAnswerの組み合わせでモックできます。

when(mockedObject.map(anyCollectionOf(Assertion.class))).thenAnswer(
     new Answer<Collection<Assertion>>() {
         @Override
         public Collection<Assertion> answer(InvocationOnMock invocation) throws Throwable {
             return new ArrayList<Assertion>();
         }
     });
3
qza