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


280

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

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

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

回答:


280

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

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

34
はい、まだ警告があります。警告を回避することは可能ですか?
odwl 2010

12
@SuppressWarnings( "unchecked")
修飾された

18
ユニットテストではモックオブジェクトについて話しているので、これは完全に許容できると思います。
Magnilex 2014年

1
@demaniakまったく機能しません。引数マッチャーはそのコンテキストでは使用できません。
KrzysztofKrasoń18年

1
@demaniakこれで問題なくコンパイルできますが、テストを実行すると、InvalidUseOfMatchersException(RuntimeException)がスローされます
Superole

277

これを回避するもう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


3
これは1.9.5で廃止されました。:(私にはあまりきれいだ。
コード修練院

12
@CodeNovitiate 1.9.5では、MockitoJUnitRunnerとMockに非推奨アノテーションを見つけることができませんでした。では、何が非推奨ですか?(はい、org.mockito.MockitoAnnotations.Mockは非推奨ですが、代わりにorg.mockito.Mockを使用してください)
neu242 '22

12
これでうまくいきました。それは単に「よりセクシー」ではなく、を使用せずに警告を回避しSuppressWarningsます。警告には理由があります。それらを抑制する習慣を身につけない方が良いでしょう。ありがとう!
Nicole

4
@Mock代わりに使用したくない点が1つありmock()ます。フィールドは構築時にnullのままであるため、そのときに依存関係を挿入できず、フィールドをfinalにすることができません。前者@Beforeはもちろん、注釈付きの方法で解決できます。
リュディガーシュルツ

3
開始するには、単にMockitoAnnotations.initMocks(this);を呼び出します。
ボルジャブ

42

指定したいジェネリック型を満たす中間クラス/インターフェースを常に作成できます。たとえば、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());

4
提供されるのFooはインターフェースまたは非最終クラスですが、これはかなりエレガントなソリューションのようです。ありがとう。
Tim Clemons 14

回答を更新して、非最終クラスの例も含めました。理想的には、インターフェイスに対してコーディングすることになりますが、常にそうなるとは限りません。良いキャッチ!
シングルトン2014

16

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

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

答えを拡張して、モックしたいクラスを渡す一般的なユーティリティメソッドを作成できます。
William Dutton、2016

1
@WilliamDutton static <T> T genericMock(Class<? super T> classToMock) { return (T)mock(classToMock); }それは単一の抑制を必要としません:)しかし、注意してください、Integer num = genericMock(Number.class)コンパイルしますがスローしClassCastExceptionます。これは、最も一般的なG<P> mock = mock(G.class)ケースでのみ役立ちます。
TWiStErRob 2016

6

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

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

3

これは興味深いケースです。メソッドはジェネリックコレクションを受け取り、同じ基本型のジェネリックコレクションを返します。例えば:

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