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);
}
}
Solved! Go to Solution.
Views
Replies
Total Likes
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:
@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 :
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:
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