Как правильно подобрать вараргов в Мокито - PullRequest
135 голосов
/ 13 апреля 2010

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

Есть какие-нибудь подсказки?

Ответы [ 9 ]

210 голосов
/ 14 апреля 2010

Представлен 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

Редактировать Новый синтаксис после устаревания:

when(a.b(anyInt(), anyInt(), ArgumentMatchers.<String>any())).thenReturn(b);
29 голосов
/ 03 ноября 2011

Несколько недокументированная функция: если вы хотите разработать собственный 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);
5 голосов
/ 30 июня 2015

Опираясь на ответ Эли Левайна, мы предлагаем более общее решение:

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")));

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

3 голосов
/ 14 ноября 2016

Я использовал код в ответе Питера Уэстмакотта, однако с Mockito 2.2.15 теперь вы можете делать следующее:

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

, где arg1, arg2, arg3 - это переменные.

1 голос
/ 29 апреля 2016

Опираясь на ответ Топчефа,

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

when(a.b(anyInt(), anyInt(), Mockito.<String>anyVararg())).thenReturn(b);
0 голосов
/ 11 апреля 2019

Вы можете сделать это, передав захват ArgumentCaptor, а затем получив varargs в виде списка, используя «getAllValues», см .: https://stackoverflow.com/a/55621731/11342928

0 голосов
/ 25 января 2019

Адаптация ответа от @topchef,

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

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

0 голосов
/ 10 февраля 2017

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

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

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

0 голосов
/ 03 мая 2016

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

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

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

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

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

...