Unit Testing Algolia Search in Java

Hi All,
I have written a small search program in Java using Algolia. Below is the code snippet.

String parentCategoryId = "CategoryId:"+categoryId;
SearchResult result = index.search(new Query("*")
            .setFilters(CategoryId));

List<Object> objResult = (List<Object>) result.getHits();   

for(int i=0; i< objResult.size(); i++) {

    Map<String, Object> myObject = (Map<String, Object>) objResult.get(i);
    JSONObject jsonObject = new JSONObject(myObject);

}

I need to write a unit test case for the above. How do I write a unit test case in Java. How do I mock an Algolia search. Please kindly help as there are no resources available for the same.

Hello,

If your intent is to mock Java client, the simplest approach is to use a mocking library like Mockito.
If however the objective is to make a real HTTP call, the Java client Github repository contains many tests to get inspired from, example: https://github.com/algolia/algoliasearch-client-java-2/blob/07acbe399e6c1d9a732b9353ad59585e158378ca/algoliasearch-core/src/test/java/com/algolia/search/integration/index/SearchTest.java

I hope that helps.

Hi,
My Intent is to mock Java client. I understand that I would need to use Mockito.
Below is a small snippet of my code:

class MyService {

public void mySearch(String categoryId) {

String parentCategoryId = "parentCategoryId:"+categoryId;

SearchResult result = index.search(new Query("*")
                       .setFilters(parentCategoryId));

}
}

My Test class : 

class MyServiceTest{

@Mock
private SearchResult searchResult;

private SearchIndex searchIndex;

@InjectMocks
private MyServiceImpl myServiceImpl;

@Test
public void testCategoryId() {

	when(searchIndex.search(new Query(anyString()).setFilters(anyString()))).thenReturn(null);
	assertEquals("NotFound", myServiceImpl.mySearch("categoryId"));
}

}

Points::

  1. I am not able to mock SearchIndex as its a final class. So when run my test case I get a NULLPointerException.
  2. Also I am not using any Model class.
  3. The input is simple a string for e.g: 1501
    4The result is in the form of : [{ “ABC”: “XYZ”, “DEF”: “GHI”}].
  4. How do I mock the call so that I can compare the input and the output.

Hi Team,

  1. Please help on the above.

  2. I went through the link mentioned by you. I have a doubt how do I match the response of the search with my response. for e.g.

    SearchIndex index =
    searchClient.initIndex(getTestIndexName(“search”), Employee.class);
    assertThat(index.findObject(x -> x.getCompany().equals(“Apple”), new Query(“Algolia”)))
    .isNull();

Please Note: I don’t have a model class. I do have an index as per below:

SearchIndex index = client.initIndex("abc");

I am not able to get my object in x -> x. ???

Please kindly let me know if you have any questions for me.

Thanks

Hi,

Yes, the link is for a real HTTP call (an integration test).

In the other hand, it is possible to mock final classes/methods.
This means you can then either mock your SearchIndex, or change your Service dependency, and depend only on the part you need from the SearchIndex.

Let’s say your Service is for query rules operations, the code could be the following:

interface MyService {
  SearchResult mySearch(String categoryId);
}

class MyServiceImpl implements MyService {

  SearchIndexSearching index;

  MyServiceImpl(SearchIndexSearching index) {
    this.index = index;
  }

  public SearchResult mySearch(String categoryId) {
    String parentCategoryId = "parentCategoryId:" + categoryId;
    return index.search(new Query("*").setFilters(parentCategoryId));
  }
}

public class MyServiceTest {

  SearchIndexSearching index;
  SearchResult searchResult;

  MyService myService;

  @Before
  public void init() {
    index = mock(SearchIndexSearching.class);
    searchResult = mock(SearchResult.class);
    myService = new MyServiceImpl(index);
  }

  @Test
  public void testCategoryId() {
    when(index.search(any())).thenReturn(searchResult);
    assertEquals(searchResult, myService.mySearch("categoryId"));
  }
}

I hope this helps!

Hi,

I was able to mock the SearchIndex class but then I am getting a NULLPointerException at the line

return index.search(new Query("*").setFilters(parentCategoryId));

Could you help me understand as to why ?

My code snippet below:

@InjectMocks
 private Product product;
private SearchIndex<Object> searchIndex;
private SearchResult<Object> result;

@Before
public void init() {
        searchIndex = mock(SearchIndex.class);
        result = mock(SearchResult.class);
}

@Test
 public void testCategoryId() {
        String[] facets = new String[]{"color", "size"};
        when(searchIndex.search(any())).thenReturn(result);
        assertEquals(result, product.getProductInfoDetails(facets, "categoryId"));
}

Hi,

It seems to be a problem with your setup and/or imports. Here is a snippet I’ve tested locally using Java 11, latest version of the Java client, JUnit 4.12, and Mockito 3.5.11 (and mock-maker-inline):

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import com.algolia.search.models.indexing.Query;
import com.algolia.search.models.indexing.SearchResult;
import java.util.Arrays;
import java.util.List;
import org.junit.Before;
import org.junit.Test;

public class MyTest {

  private Product product;
  private SearchIndex<Object> searchIndex;
  private SearchResult<Object> result;

  @Before
  public void init() {
    searchIndex = mock(SearchIndex.class);
    result = mock(SearchResult.class);
    product = new Product(searchIndex);
  }

  @Test
  public void testCategoryId() {
    List<String> facets = Arrays.asList("color", "size");
    when(searchIndex.search(any())).thenReturn(result);
    assertEquals(result, product.getProductInfoDetails(facets, "categoryId"));
  }
}

class Product {

  SearchIndex index;

  Product(SearchIndex index) {
    this.index = index;
  }

  public SearchResult getProductInfoDetails(List<String> facets, String categoryId) {
    String parentCategoryId = "parentCategoryId:" + categoryId;
    return index.search(new Query("*").setFacets(facets).setFilters(parentCategoryId));
  }
}

I hope this solves your issue!