web-dev-qa-db-ja.com

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

私は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引数を完全に省略したにもかかわらず、これは機能します。

手がかりはありますか?

139
qualidafial

Mockito 1.8.1が導入されました anyVararg()matcher

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

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

Edit廃止後の新しい構文:

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

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

例えば:

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);
30
Eli Levine

ここでの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")));

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

5

私はPeter Westmacottの回答のコードを使用していますが、Mockito 2.2.15では次のことができるようになりました。

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

どこ arg1, arg2, arg3は可変引数です。

3
Mark

Topchefの答えに基づいて、

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

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

@topchefからの回答を適応させ、

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

Java Mockito 2.23.4のドキュメント、Mockito.any() "nullやvarargsを含むあらゆるものに一致します。"

0
Craig

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

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

この場合、明示的にbyte arrayにキャストする必要があります。

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

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

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

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

たとえば、タイプをチェックして適切にキャストしたり、リストに追加したりします。

0