Как правильно сопоставить 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 при выполнении этого метода.
Любые подсказки?
Ответы
Ответ 1
В 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);
Ответ 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() "Совпадает с чем угодно, включая нули и переменные".