Capturing methods arguments with Mockito

In my project, we developed an API for searching on the lines of Hibernate Restrictions API. It was for Solr search. A sample code looked something like

 public SearchResults searchApprovedRecipes(String searchText, Integer pageNum) {
 SolrSearchServiceImpl.PageCounter pageCounter = new SolrSearchServiceImpl.PageCounter(pageNum);

 SearchCriteria searchCriteria = new SearchCriteria(SearchCriteria.SearchType.RECIPE);
 searchCriteria.add(SearchCriteria.SearchField.NAME, searchText);
 searchCriteria.add(SearchCriteria.SearchField.STATUS, WorkflowStatus.APPROVED.name(), WorkflowStatus.EDITED.name());
 searchCriteria.setMaxResults(pageCounter.getMaxResults());
 searchCriteria.setStart(pageCounter.getStart());

 SearchResults searchResults = getRestTemplate().postForObject(getSearchUrl(), searchCriteria, SearchResults.class);

 return searchResults;

Now, if you talk about unit testing, there is nothing much to test, except mocking calls to rest template. The main purpose of this method is to build SearchCriteria. So, if somehow, we can mock SearchCriteria, then we could test that.

Mockito comes with a concept of capturing the arguments passed to the mocked calls (in this case, call to RestTemplate would be mocked), using ArgumentCaptor, which captures argument values for further assertion.

Following is the unit test case of the above method.

@Test
 public void testSearchApprovedRecipes() {
 ArgumentCaptor<SearchCriteria> searchCriteriaArgumentCaptor = ArgumentCaptor.forClass(SearchCriteria.class);
 String test = "test";
 solrSearchService.searchApprovedRecipes(test, 1);
 verify(restTemplate, times(1)).postForObject(eq(SEARCH_URL), searchCriteriaArgumentCaptor.capture(), eq(SearchResults.class));

SearchCriteria searchCriteria = searchCriteriaArgumentCaptor.getValue();
 Assert.assertEquals(2, searchCriteria.getSearchFields().size());
 Assert.assertEquals(SearchCriteria.SearchType.RECIPE, searchCriteria.getSearchType());
 Assert.assertEquals(test, searchCriteria.get(SearchCriteria.SearchField.NAME).get(0));
 Assert.assertTrue(searchCriteria.get(SearchCriteria.SearchField.STATUS).contains( WorkflowStatus.APPROVED.name()));
 Assert.assertTrue(searchCriteria.get(SearchCriteria.SearchField.STATUS).contains( WorkflowStatus.EDITED.name()));
 }

In the above code, you can see that first we created a ArgumentCaptor for the SearchCriteria class, and then, while mocking call to the RestTemplate, instead of passing the SearchCriteria object, we passed the ArgumentCaptor and all the changes made to the SearchCriteria inside the method are captured in the ArgumentCaptor. Now, once the method calls return, we can have assert statements against the ArgumentCaptor. This way, we can test the SearchCriteria.

Leave a comment