mockito wywołania zwrotne i pobieranie wartości argumentów

88

Nie mam szczęścia, aby Mockito przechwytywał wartości argumentów funkcji! Kpię z indeksu wyszukiwarki i zamiast budować indeks, używam tylko skrótu.

// 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))

Nie mogę używać dowolnych argumentów, ponieważ testuję wyniki zapytań (tj. Które dokumenty zwracają). Podobnie nie chcę określać konkretnej wartości i mieć wiersz dla każdego dokumentu!

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

Przejrzałem sekcję wywołań zwrotnych na stronie Korzystanie z Mockito . Niestety, to nie jest Java i nie mogłem uzyskać własnej interpretacji tego do pracy w Javie.

EDYCJA (dla wyjaśnienia): Jak zmusić Mockito do przechwycenia argumentu X i przekazania go do mojej funkcji? Chcę dokładnej wartości (lub ref) X przekazanej do funkcji.

Nie chcę wyliczać wszystkich przypadków, a dowolny argument nie zadziała, ponieważ testuję różne wyniki dla różnych zapytań.

Mówi strona Mockito

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

To nie jest java i nie wiem, jak przetłumaczyć na język java ani przekazać tego, co się stało, do funkcji.

nflacco
źródło
Nie jestem pewien, czy dokładnie rozumiem, co ci się nie udaje. Twoje wywołanie Mockito.when(reader.document(666)).thenReturn(document(fakeIndex(666))powinno ustawić dla ciebie obiekt pozorowany. Co się dzieje, kiedy dzwonisz reader.document(666)?
dużą zawartością kofeiny
666 działa dobrze. Chciałbym jednak móc przekazać konkretną liczbę X i uzyskać wynik fakeIndex (X). Mam dużą liczbę potencjalnych dokumentów do przetestowania pod kątem zapytań i nie chcę wprowadzać ich wszystkich.
nflacco

Odpowiedzi:

103

Nigdy nie korzystałem z Mockito, ale chcę się uczyć, więc proszę bardzo. Jeśli ktoś mniej wiedzący ode mnie odpowie, najpierw wypróbuj jego odpowiedź!

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]));
     }
 });
Ed Staub
źródło
2
Właśnie zauważyłem link po prawej stronie do Mockito: Jak sprawić, by metoda zwracała argument, który został do niej przekazany . Wygląda na to, że jestem blisko, jeśli nie na miejscu.
Ed Staub,
silna reputacja użytkownika (666) z oryginalną korelacją pytań! To działało bardzo dobrze. Jedyna zmiana, którą wprowadziłem, aby uzyskać kompilację, została upubliczniona przed odpowiedzią obiektu (wywołanie InvocationOnMock) ....
nflacco
54

Sprawdź 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());
    }
  });
Qualidafial
źródło
3
Wow, nie wiedziałem, że możesz użyć ArgumentCaptors do zarostu. W tym linku jest jednak wielkie ostrzeżenie na ten temat. Postępuj ostrożnie.
einnocenty
3
Tak, masz rację. Captors powinien być używany tylko z weryfikacją.
kwalifikacyjny mecz
41

Możesz chcieć użyć weryfikacji () w połączeniu z ArgumentCaptor, aby zapewnić wykonanie w teście i ArgumentCaptor, aby ocenić argumenty:

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

Wartość argumentu jest oczywiście dostępna poprzez argument.getValue () w celu dalszej manipulacji / sprawdzania lub czegokolwiek innego, co chcesz zrobić.

fl0w
źródło
2
najlepsza odpowiedź: prosta, łatwa do zrozumienia
Radu Cugut
Nie odpowiada na pytanie. Pytanie dotyczy Mockito. Kiedy i nie weryfikuj.
seBaka28
@ seBaka28 najlepszym sposobem uzyskiwania argumentów jest przechwytywanie argumentów. Zdecydowanie zaleca się używanie ArgumentCaptors z weryfikacją przez autorów Mockito, dlatego chciałem udzielić pełnej odpowiedzi perspektywicznej. jeśli zdecydujesz się ich nie używać, to jest twój wybór, ale nie jest to zalecane. EDYCJA: Nie rozumiem, jak to usprawiedliwia głos przeciw, ale jest to również Twój wybór.
fl0w
1
Ponieważ nie odpowiada na pytanie. Tak, ArgumentCaptor jest świetny, gdy chcesz przechwycić argument, ale nie możesz go używać w połączeniu z when (...). ThenReturn (), co jest tym, co próbuje zrobić OP: Na podstawie określonego parametru, fałszywa usługa ma zwrócić określony obiekt.
seBaka28
1
@YuraHoy, który jest standardowym komunikatem o błędzie, gdy używasz weryfikacji, a obiekt lub metoda jest wywoływana częściej niż powiedziałeś, że weryfikujesz, aby się spodziewać. Możesz zmienić liczbę oczekiwań, dodając argument times (n) w następujący sposób: verify (reader, times (5)) - to oczekiwałoby 5 interakcji. Więcej informacji można znaleźć na stronie: baeldung.com/mockito-verify
fl0w
13

W Javie 8 może to wyglądać mniej więcej tak:

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

Zakładam, że documentto mapa.

Jean-François Beauchef
źródło