Expand my Community achievements bar.

SOLVED

unit testing of query, querybuilder, session from resourceresolver

Avatar

Level 7

Hi All,

 

I have set up test content json for below source code.

Is it possible to have a real resource resolver, query builder, query, session to go through test content json get me the results.

 

All the unit-test examples out there on internet talking about mocking  query, querybuilder, session, searchresult, objects and do mockito returns rather than performing real query search on test content json.

 

I am looking to test query in below source code to do real querying on test content json and give results back.

 

I appreciate any help! NOTE: resource resolver that comes with test aemcontext can adapt to pagemanger but not not to querybuilder or serssion.

I would like to know if it is possible or not , if so , any small example would be appreciated.

 

private void getFaqs() {

        try {
            QueryBuilder queryBuilder = resourceResolver.adaptTo(QueryBuilder.class);
            if (queryBuilder == null) {
                LOG.warn("Query builder was null therefore no query was executed");
                return;
            }

            if (contentFragmentsList != null) {
                Map<String, String> cfVariationMap = new HashMap<>();

                Map<String, String> queryParameterMap = new HashMap<>();
                queryParameterMap.put("type", "dam:AssetContent");
                queryParameterMap.put("property", "data/cq:model");
                queryParameterMap.put("property.value", "/conf/test-project/simple-model/settings/dam/cfm/models/faq-model");

                queryParameterMap.put("group.p.or", "true");


                IntStream.range(1, contentFragmentsList.size() + 1)
                        .forEach(faqIndex -> {
                            if (contentFragmentsList.get(faqIndex - 1).getFragmentPath() != null && !contentFragmentsList.get(faqIndex - 1).getFragmentPath().isEmpty()) {
                                queryParameterMap.put("group." + faqIndex + "_group.path", contentFragmentsList.get(faqIndex - 1).getFragmentPath());

                                if(contentFragmentsList.get(faqIndex - 1).getVariationName() != null && !contentFragmentsList.get(faqIndex - 1).getVariationName().isEmpty()){
                                    cfVariationMap.put(contentFragmentsList.get(faqIndex-1).getFragmentPath(), contentFragmentsList.get(faqIndex-1).getVariationName());
                                }
                                if (contentFragmentsList.get(faqIndex - 1).getCategory() != null && contentFragmentsList.get(faqIndex - 1).getCategory().length > 0) {
                                    queryParameterMap.put("group." + faqIndex + "_group.property.or", "true");
                                    queryParameterMap.put("group." + faqIndex + "_group.property", "data/master/cq:tags");
                                    IntStream.range(1, contentFragmentsList.get(faqIndex - 1).getCategory().length + 1).forEach(tagIndex -> {
                                        queryParameterMap.put("group." + faqIndex + "_group.property." + tagIndex + "_value", contentFragmentsList.get(faqIndex - 1).getCategory()[tagIndex - 1]);
                                    });
                                }
                            }
                        });


                if ("title".equalsIgnoreCase(orderBy)) {
                    queryParameterMap.put("orderby", "@" + JcrConstants.JCR_TITLE);
                    queryParameterMap.put("orderby.sort", sortOrder);
                }

                queryParameterMap.put("p.limit", Integer.toString(100));

                LOG.debug("FAQ Query Map: '{}'", queryParameterMap);


                PredicateGroup predicateGroup = PredicateGroup.create(queryParameterMap);
                Query query = queryBuilder.createQuery(predicateGroup, resourceResolver.adaptTo(Session.class));

                SearchResult searchResult = query.getResult();

                faqs = searchResult.getHits().stream()
                        .map(hit -> {
                            try {
                                FAQContentFragment faqCF= Objects.requireNonNull(resourceResolver.resolve(hit.getPath()).getParent()).adaptTo(FAQContentFragment.class);
                                if (faqCF != null) {

                                    String cfPath = substringBefore(hit.getPath(), "/jcr:content");
                                    String variationName=cfVariationMap.get(cfPath);

                                    if(variationName != null){
                                        faqCF.setVariationName(variationName);
                                    }else{
                                        faqCF.setVariationName("master");
                                    }

                                }
                                return faqCF;
                            } catch (RepositoryException e) {
                                LOG.error("Error collecting search results", e);
                                return null;
                            }
                        })
                        .filter(Objects::nonNull)
                        .collect(Collectors.toList());
            }
        } catch (Exception e) {
            LOG.error("exception" , e);
        }
    }

 

 

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

This way you can mock the ResourceResolver, QueryBuilder, Query, and Session objects using

Mockito

// Mock objects
@Mock
private ResourceResolver resourceResolver;
@Mock
private QueryBuilder queryBuilder;
@Mock
private Query query;
@Mock
private Session session;
@Mock
private SearchResult searchResult;

// When-Then mocking
when(resourceResolver.adaptTo(QueryBuilder.class)).thenReturn(queryBuilder);
when(resourceResolver.adaptTo(Session.class)).thenReturn(session);
when(queryBuilder.createQuery(any(PredicateGroup.class), eq(session))).thenReturn(query);
when(query.getResult()).thenReturn(searchResult);

// Your test method here

In this code, @Mock creates mock objects, and when().thenReturn() specifies the output of the method...1.

Please note that this is a basic example. You might need to add more mocking depending on your test cases. Also, remember to add @RunWith(MockitoJUnitRunner.class) at the class level to initialize these mock...1.

For more information about Mockito and unit testing in AEM, you can refer to these resources:

 

View solution in original post

3 Replies

Avatar

Community Advisor

@sreenu539 Any specific reason why you want a real object instead of the mock objects provided by the testing API?

If you want to test the query performance, then you can simply get real production content synced to your local environment and look at the query performance using tools like Explain Query.

Based on the results , you can then further look at any optimization opportunities by considering aspects like creating an index, modify the query itself , evaluate whether or not ordering is important for your use case or not etc.

 

More details on how you can optimize your query performance : 

https://experienceleague.adobe.com/docs/experience-manager-cloud-service/content/operations/query-an...

 

Avatar

Correct answer by
Community Advisor

This way you can mock the ResourceResolver, QueryBuilder, Query, and Session objects using

Mockito

// Mock objects
@Mock
private ResourceResolver resourceResolver;
@Mock
private QueryBuilder queryBuilder;
@Mock
private Query query;
@Mock
private Session session;
@Mock
private SearchResult searchResult;

// When-Then mocking
when(resourceResolver.adaptTo(QueryBuilder.class)).thenReturn(queryBuilder);
when(resourceResolver.adaptTo(Session.class)).thenReturn(session);
when(queryBuilder.createQuery(any(PredicateGroup.class), eq(session))).thenReturn(query);
when(query.getResult()).thenReturn(searchResult);

// Your test method here

In this code, @Mock creates mock objects, and when().thenReturn() specifies the output of the method...1.

Please note that this is a basic example. You might need to add more mocking depending on your test cases. Also, remember to add @RunWith(MockitoJUnitRunner.class) at the class level to initialize these mock...1.

For more information about Mockito and unit testing in AEM, you can refer to these resources:

 

Avatar

Community Advisor

I think the approach provided by @pulkitvashisth is the best way to test it, theoretically, you don't need to test the Search API that's why mocking all that processing is ok, what you can do further is to return your resources loaded from a JSON file, that way you have control over what things will be returned, see below as example:

 

 

Query mockQuery = mock(Query.class);
SearchResult mockSearchResult = mock(SearchResult.class);

when(mockQueryBuilder.createQuery(any(), any())).thenReturn(mockQuery);
when(mockQuery.getResult()).thenReturn(mockSearchResult);
//Mocking the first result from the query
Hit result1 = mock(Hit.class); 
//This will allow you to load a resource previously loaded via context.load().json()
when(result1.getResource()).thenReturn(context.currentResource("/content/myfolder/jcr:content"));
List<Hit> mockedHits = new ArrayList<>();
mockedHits.add(result1);
when(mockSearchResult.getHits()).thenReturn(mockedHits);

 

 

Hope this helps



Esteban Bustamante