Подтвердить что ты не робот

Как правильно сопоставить varargs в Mockito

Я пытаюсь высмеять метод с параметрами vararg с помощью 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 при выполнении этого метода.

Любые подсказки?

4b9b3361

Ответ 2

Немного недокументированная функция. Если вы хотите разработать пользовательский Matcher, который соответствует аргументам vararg, вам нужно, чтобы он реализовал org.mockito.internal.matchers.VarargMatcher, чтобы он работал правильно. Это пустой интерфейс маркера, без которого Mockito не будет правильно сравнивать аргументы при вызове метода с varargs с помощью вашего 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);

Ответ 3

Основываясь на 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")));

(Очевидно, статический импорт сделает это более читаемым.)

Ответ 4

Я использовал код в Peter Westmacott, но, учитывая Mockito 2.2.15, вы можете сделать следующее:

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

где arg1, arg2, arg3 - varargs.

Ответ 5

Основываясь на ответе topchef,

Для 2.0.31-бета мне пришлось использовать Mockito.anyVararg вместо Matchers.anyVararrg:

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

Ответ 6

В моем случае сигнатура метода, который я хочу записать, это:

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

В этом случае вы должны явно указать байтовый массив:

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

Я использую версию mockito 1.10.19

Ответ 7

Вы также можете перебирать аргументы:

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

например, проверьте их типы и примените их соответствующим образом, добавьте в список или что-то еще.

Ответ 8

Приспосабливая ответ от @topchef,

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

В соответствии с документами Java для Mockito 2.23.4, Mockito.any() "Совпадает с чем угодно, включая нули и переменные".