web-dev-qa-db-ja.com

Mockito @InjectMocksは、同じタイプのフィールドでは機能しません

次の簡単なコード例が、1.8.5を超えるすべてのMockitoバージョンで機能するとは限らないことに非常に驚きました。

@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {

    @Mock(name = "b2")
    private B b2;

    @InjectMocks
    private A a;

    @Test
    public void testInjection() throws Exception {
        assertNotNull(a.b2); //fails
        assertNull(a.b1); //also fails, because unexpectedly b2 mock gets injected here
    }

    static class A{
        private B b1;
        private B b2;
    }

    interface B{}
}

Javadocs( http://docs.mockito.googlecode.com/hg/latest/org/mockito/InjectMocks.html )に引用符があります:

注1:同じタイプ(または同じ消去)のフィールドがある場合は、すべての@Mockアノテーション付きフィールドに一致するフィールドの名前を付けることをお勧めします。そうしないと、Mockitoが混乱し、インジェクションが発生しません。

同じタイプのフィールドが複数ある場合、そのうちの1つだけをモックすることはできず、[〜#〜] all [〜#〜に対して@Mockを定義する必要があるということですか? ]同じタイプのフィールド?それは既知の制限であり、まだ修正されていない理由はありますか? @Mockをフィールド名で一致させるのは簡単なはずですよね。

16

Mockitoは 彼らのJavaDoc で説明されているアルゴリズムを使用しているようです

私が正しく理解していれば、最初にタイプ(この場合は1 Bのみ)でソートし、次に名前(ここでは変更なし)でソートします。最終的に OngoingInjectorインターフェイスの実装 を使用して注入します。これは、最初のフィールドを検索して注入するように見えます。

定義されているBは1つだけで、モックにはBのフィールドが2つあるため、最初のインスタンスがフィールドに一致することが確認され、停止します。これは、 NameBasedCandidateFiltermocks.size() == 1が原因です。したがって、フィルタリングを停止して直接注入します。同じタイプのモックを複数作成すると、名前でソートされ、それに応じて注入されます。

特定のタイプの複数のモック(ただし、フィールドの数より少ない)を作成したときに、それを機能させることができました。

@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {

    @Mock(name = "b2")
    private B b2;

    @Mock(name = "b3")
    private B b3;

    @InjectMocks
    private A a;

    @Test
    public void testInjection() {
        System.out.println(this.a);
    }

    static class A {

        private B b1;

        private B b2;

        private B b3;
    }

    interface B {
    }
}

これにより、a.b1とa.b2(Aで定義されている最初の2つのフィールド)ではなく、b2がa.b2に、b3がa.b3に正しく挿入されます。

確認するために、インジェクションフィルタリングアルゴリズムの機能強化または変更を加えて、GitHubの問題をリポジトリにいつでも残すことができます。

21

同じタイプのモックが複数存在する場合、これは回避策としてmockitoに文書化されています。指定された名前(つまり、@Mock(name = "b2"))に基づいて実装を解決することはありません。実装を解決するために使用するアルゴリズムは、注入された依存関係のフィールド名によるものです。したがって、上記のコードは正しく解決されます(b2 => @Mock private B b2およびb3 => @Mock private B b3)。

他の回避策は、依存性を注入するための推奨される方法であるコンストラクター注入を使用することです。

0
alltej