обратные вызовы mockito и получение значений аргументов

88

Мне не удалось заставить Mockito захватывать значения аргументов функции! Я издеваюсь над индексом поисковой системы и вместо того, чтобы строить индекс, я просто использую хеш.

// Fake index for solr
Hashmap<Integer,Document> fakeIndex;

// Add a document 666 to the fakeIndex
SolrIndexReader reader = Mockito.mock(SolrIndexReader.class);

// Give the reader access to the fake index
Mockito.when(reader.document(666)).thenReturn(document(fakeIndex(666))

Я не могу использовать произвольные аргументы, потому что я проверяю результаты запросов (т.е. какие документы они возвращают). Точно так же я не хочу указывать конкретное значение и иметь строку для каждого документа!

Mockito.when(reader.document(0)).thenReturn(document(fakeIndex(0))
Mockito.when(reader.document(1)).thenReturn(document(fakeIndex(1))
....
Mockito.when(reader.document(n)).thenReturn(document(fakeIndex(n))

Я просмотрел раздел обратных вызовов на странице « Использование Mockito» . К сожалению, это не Java, и я не мог получить собственную интерпретацию этого для работы на Java.

ИЗМЕНИТЬ (для пояснения): Как заставить Mockito захватить аргумент X и передать его в мою функцию? Я хочу, чтобы точное значение (или ссылка) X было передано функции.

Я не хочу перечислять все случаи, и произвольный аргумент не сработает, потому что я проверяю разные результаты для разных запросов.

На странице Mockito говорится

val mockedList = mock[List[String]]
mockedList.get(anyInt) answers { i => "The parameter is " + i.toString } 

Это не java, и я не знаю, как перевести на java или передать то, что произошло, в функцию.

nflacco
источник
Я не уверен, что понимаю, что именно у вас не получается. Ваш вызов Mockito.when(reader.document(666)).thenReturn(document(fakeIndex(666))должен настроить для вас фиктивный объект. Что происходит, когда вы звоните reader.document(666)?
сильно кофеин 09
666 работает нормально. Однако я хотел бы иметь возможность передать конкретное число X и получить результат fakeIndex (X). У меня есть большое количество потенциальных документов для проверки запросов, и я не хочу вводить их все.
nflacco 09

Ответы:

103

Я никогда не использовал Mockito, но хочу научиться, так что начнем. Если ответит кто-то менее невежественный, чем я, сначала попробуйте его ответ!

Mockito.when(reader.document(anyInt())).thenAnswer(new Answer() {
 public Object answer(InvocationOnMock invocation) {
     Object[] args = invocation.getArguments();
     Object mock = invocation.getMock();
     return document(fakeIndex((int)(Integer)args[0]));
     }
 });
Эд Стауб
источник
2
Я только что заметил ссылку справа на Mockito: как заставить метод возвращать переданный ему аргумент . Похоже, я близок, если не на месте.
Эд Стауб
сильная репутация пользователей (666) и исходное соотношение вопросов! Это сработало очень хорошо. Только изменение, которое я сделал для компиляции материала, было опубликовано перед ответом объекта (вызов InvocationOnMock) ....
nflacco 09
54

Проверьте ArgumentCaptors:

https://site.mockito.org/javadoc/current/org/mockito/ArgumentCaptor.html

ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass(Integer.class);
Mockito.when(reader.document(argument.capture())).thenAnswer(
  new Answer() {
    Object answer(InvocationOnMock invocation) {
      return document(argument.getValue());
    }
  });
квалидафиал
источник
3
Вау, я не знал, что вы можете использовать ArgumentCaptors для заглушки. Однако в этой ссылке есть большое предупреждение об этом. Действовать с осторожностью.
einnocent
3
Ага, ты прав. Захватчики следует использовать только при проверках.
qualidafial
41

Вы можете использовать verify () в сочетании с ArgumentCaptor, чтобы гарантировать выполнение в тесте, и ArgumentCaptor для оценки аргументов:

ArgumentCaptor<Document> argument = ArgumentCaptor.forClass(Document.class);
verify(reader).document(argument.capture());
assertEquals(*expected value here*, argument.getValue());

Очевидно, что значение аргумента доступно через arguments.getValue () для дальнейших манипуляций / проверки или того, что вы хотите сделать.

fl0w
источник
2
лучший ответ: прямо, легко понять
Radu Cugut
Не отвечает на вопрос. Вопрос по поводу Mockito.when и не проверять.
seBaka28
@ seBaka28 лучшее решение для получения аргументов - это захват аргументов. Авторы Mockito настоятельно рекомендуют использовать ArgumentCaptors с verify, поэтому я хотел дать полный перспективный ответ. если вы сами решите не использовать их, это ваш выбор, но не рекомендуется. РЕДАКТИРОВАТЬ: Я не понимаю, как это оправдывает отрицательный голос, но это также ваш выбор.
fl0w,
1
Потому что это не отвечает на вопрос. Да, ArgumentCaptor отлично подходит, когда вы хотите захватить аргумент, но вы не можете использовать его вместе с when (...). ThenReturn (), что пытается сделать OP: на основе определенного параметра, имитация службы должен возвращать определенный объект.
seBaka28,
1
@YuraHoy, это стандартное сообщение об ошибке, когда вы используете verify, и объект или метод вызывается чаще, чем вы сказали, что verify ожидать. Вы можете изменить счетчик ожидания, добавив аргумент times (n) следующим образом: verify (reader, times (5)) - это ожидает 5 взаимодействий. Для справки: baeldung.com/mockito-verify
fl0w
13

В Java 8 это могло быть примерно так:

Mockito.when(reader.document(anyInt())).thenAnswer(
  (InvocationOnMock invocation) -> document(invocation.getArguments()[0]));

Я предполагаю, что documentэто карта.

Жан-Франсуа Бошеф
источник