Я думаю, что есть несколько способов добиться желаемого поведения.
1.Управлять порядком совпадений в стеке
Это не тот путь, по которому можно идти!
Кажется, что matcherStack
является внутренним для Mockito.
У них есть метод pullLocalizedMatchers
из стека и reportMatcher
метод для добавления ArgumentMatcher
в стек.К ним можно получить доступ через
org.mockito.internal.progress.ThreadSafeMockingProgress
.mockingProgress()
.getArgumentMatcherStorage()
Таким образом, теоретически вы можете выбрать этот путь, но решение будет хрупким, потому что вы возитесь с внутренностями Mockito.Они могут измениться без уведомления в последующих версиях Mockito.
К счастью, есть пара альтернатив.
2.Управляйте порядком, в котором в первую очередь регистрируются сопоставители
, используя функциональный интерфейс Java 8 Supplier
(Это соответствует этому ответу , заданному @ToYonos)
Сопоставители автоматически регистрируются Mockito при вызове методов, их создающих (eq
, argThat
, any
, isNotNull
, ...).Но вы можете отложить вызов этих методов, передав Supplier
для каждого из этих сопоставителей.Затем удобный метод управляет порядком, в котором он выполняет этих поставщиков.
public String callOnMock(Supplier<Integer> argument2) {
return mock.call(eq(1), argument2.get(), argThat(i -> i >= 3));
}
when(callOnMock(() -> eq(2))).thenReturn("result");
Использование его выглядит несколько иначе, чем обычный стиль Mockito.
Необходимо соблюдать особую осторожность.если вы предлагаете удобные методы для тех поставщиков, которые используют / агрегируют другие сопоставители, из-за той же проблемы.
callOnMock(() -> AdditionalMatchers.and(isNotNull(), eq(2)))
будет работать,
, но это не будет:
public Supplier<Integer> and(int matcher1, int matcher2){
return () -> AdditionalMatchers.and(matcher1, matcher2);
}
callOnMock(and(isNotNull(), eq(2)))
Это накладывает некоторую ответственность на пользователя ваших методов.Они должны убедиться, что никто из участников не будет вызван случайно.
3.Управление порядком, в котором макеты ожидают совпадений
Делегирование ложных вызовов другому фиктивному объекту может дать вам контроль над порядком аргументов.
Вы должны будете определить интерфейс, который ожидает совпадения в порядке,вспомогательный метод получает их, помещая те, которые добавляются вспомогательным методом, в конце.
Ожидания должны быть сделаны в отношении этого интерфейса делегата.
public interface MockDelegate {
String call(Integer i1, Integer i0, Integer i2);
}
@Mock
private MockDelegate delegate;
@Before
public void setUp() {
when(mock.call(any(), any(), any()))
.thenAnswer(invocation -> delegate.call(
invocation.getArgument(1), // this delegates the call
invocation.getArgument(0), // but flips the first two arguments
invocation.getArgument(2)
));
}
public String callOnMock(int argument2) {
return delegate.call(argument2, eq(1), argThat(i -> i >= 3));
}
Это можно использовать с обычными сопоставителями стиля Mockito:
when(callOnMock(eq(2))).thenReturn("result");