Mockitoで可変引数を適切に一致させる方法


152

私はMockitoを使用して、可変引数パラメーターを持つメソッドをモックしようとしています:

interface A {
  B b(int x, int y, C... c);
}

A a = mock(A.class);
B b = mock(B.class);

when(a.b(anyInt(), anyInt(), any(C[].class))).thenReturn(b);
assertEquals(b, a.b(1, 2));

これは機能しませんが、代わりにこれを行うと:

when(a.b(anyInt(), anyInt())).thenReturn(b);
assertEquals(b, a.b(1, 2));

これは機能しますが、メソッドをスタブするときにvarargs引数を完全に省略しています。

手がかりはありますか?


最後の例が機能するという事実は、varargsパラメーターがゼロの場合と一致するため、かなり簡単です。
topchef 2010

回答:


235

Mockito 1.8.1はanyVararg()マッチャーを導入しました

when(a.b(anyInt(), anyInt(), Matchers.<String>anyVararg())).thenReturn(b);

これの履歴も参照してください:https : //code.google.com/archive/p/mockito/issues/62

サポート終了後に新しい構文を編集します。

when(a.b(anyInt(), anyInt(), ArgumentMatchers.<String>any())).thenReturn(b);

26
anyVararg()戻り値の型としてObjectがあります。var arg型(たとえば、String ...、Integer ...など)と互換性を持たせるには、明示的にキャストします。たとえばdoSomething(Integer number, String ... args)、モック/スタブコードをのようなもので実行できる場合when(mock).doSomething(eq(1), (String) anyVarargs())。これでコンパイルエラーが解決されます。
サイコパンチ

15
infoのanyVarargは非推奨になりました: "@deprecated as 2.1.0 use any()"
alexbt

5
Matchersorg.hamcrest.Matchersクラスとの名前の衝突を避けるために非推奨になり、mockito v3.0で削除される可能性があります。ArgumentMatchers代わりに使用してください。
JonyD 2017

31

ややドキュメント化されていない機能:vararg引数に一致するカスタムMatcherを開発する場合は、org.mockito.internal.matchers.VarargMatcher正しく動作するように実装する必要があります。これは空のマーカーインターフェースであり、Mockitoがマッチャーを使用してvarargsでメソッドを呼び出すときに、引数を正しく比較しません。

例えば:

class MyVarargMatcher extends ArgumentMatcher<C[]> implements VarargMatcher {
    @Override public boolean matches(Object varargArgument) {
        return /* does it match? */ true;
    }
}

when(a.b(anyInt(), anyInt(), argThat(new MyVarargMatcher()))).thenReturn(b);

7

ここでのEli Levineの答えに基づいて構築すると、より一般的なソリューションになります。

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.mockito.ArgumentMatcher;
import org.mockito.internal.matchers.VarargMatcher;

import static org.mockito.Matchers.argThat;

public class VarArgMatcher<T> extends ArgumentMatcher<T[]> implements VarargMatcher {

    public static <T> T[] varArgThat(Matcher<T[]> hamcrestMatcher) {
        argThat(new VarArgMatcher(hamcrestMatcher));
        return null;
    }

    private final Matcher<T[]> hamcrestMatcher;

    private VarArgMatcher(Matcher<T[]> hamcrestMatcher) {
        this.hamcrestMatcher = hamcrestMatcher;
    }

    @Override
    public boolean matches(Object o) {
        return hamcrestMatcher.matches(o);
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("has varargs: ").appendDescriptionOf(hamcrestMatcher);
    }

}

その後、hamcrestの配列マッチャーと一緒に使用できます。

verify(a).b(VarArgMatcher.varArgThat(
            org.hamcrest.collection.IsArrayContaining.hasItemInArray("Test")));

(明らかに、静的インポートはこれを読みやすくします。)


いいね。これはMockito IMOに組み込む必要があります。
ブライアント2015

私はこのようなものを追加するためにHamcrestに対して問題を提出しました。github.com/mockito/mockito/issues/356を
マーク

これはMockito 1用ですか?2.10に対してコンパイルしようとすると、さまざまなコンパイルエラーが発生します。
フランス2018

@Frans私がこの回答を書いたとき、2リリースはまだベータ版だったようです。そのため、おそらくMockito v1.10.19またはその周辺向けに書かれたものです。(github.com/mockito/mockito/releases)おそらく更新可能です... :-D
Peter Westmacott

3

Peter Westmacottの回答でコードを使用してきましたが、Mockito 2.2.15を使用すると、次のことができます。

verify(a).method(100L, arg1, arg2, arg3)

arg1, arg2, arg3varargsはどこですか。


1

トップシェフの答えに基づいて、

2.0.31-betaでは、Matchers.anyVararrgの代わりにMockito.anyVarargを使用する必要がありました。

when(a.b(anyInt(), anyInt(), Mockito.<String>anyVararg())).thenReturn(b);

3
infoのanyVarargは非推奨になりました: "@deprecated as 2.1.0 use any()"
alexbt

0

私の場合、引数を取得したいメソッドのシグネチャは次のとおりです。

    public byte[] write(byte ... data) throws IOException;

この場合、バイト配列に明示的にキャストする必要があります

       when(spi.write((byte[])anyVararg())).thenReturn(someValue);

私はmockitoバージョンを使用しています 1.10.19


0

引数をループすることもできます:

Object[] args = invocation.getArguments(); 
for( int argNo = 0; argNo < args.length; ++argNo) { 
    // ... do something with args[argNo] 
}

たとえば、型を確認して適切にキャストしたり、リストに追加したりします。


0

@topchefからの回答を採用して、

Mockito.when(a.b(Mockito.anyInt(), Mockito.anyInt(), Mockito.any())).thenReturn(b);

Mockito 2.23.4のJavaドキュメントによれば、Mockito.any()は「nullやvarargsを含むすべてのものに一致します。」


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