mockito callbacks and getting argument values

JavaUnit TestingMockingMockito

Java Problem Overview


I'm not having any luck getting Mockito to capture function argument values! I am mocking a search engine index and instead of building an index, I'm just using a hash.

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

I can't use arbitrary arguments because I'm testing the results of queries (ie which documents they return). Likewise, I don't want to specify a specific value for and have a line for each document!

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

I looked at the callbacks section on the Using Mockito page. Unfortunately, it isn't Java and I couldn't get my own interpretation of that to work in Java.

EDIT (for clarification): How do I get get Mockito to capture an argument X and pass it into my function? I want the exact value (or ref) of X passed to the function.

I do not want to enumerate all cases, and arbitrary argument won't work because I'm testing for different results for different queries.

The Mockito page says

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

That's not java, and I don't know how to translate into java or pass whatever happened into a function.

Java Solutions


Solution 1 - Java

I've never used Mockito, but want to learn, so here goes. If someone less clueless than me answers, try their answer first!

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]));
     }
 });

Solution 2 - Java

Check out 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());
    }
  });

Solution 3 - Java

You might want to use verify() in combination with the ArgumentCaptor to assure execution in the test and the ArgumentCaptor to evaluate the arguments:

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

The argument's value is obviously accessible via the argument.getValue() for further manipulation / checking or whatever you wish to do.

Solution 4 - Java

With Java 8, this could be something like this:

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

I am assuming that document is a map.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionnflaccoView Question on Stackoverflow
Solution 1 - JavaEd StaubView Answer on Stackoverflow
Solution 2 - JavaqualidafialView Answer on Stackoverflow
Solution 3 - Javafl0wView Answer on Stackoverflow
Solution 4 - JavaJean-François BeauchefView Answer on Stackoverflow