Expand my Community achievements bar.

SOLVED

AEM Servlet junit writing which using querybuilder

Avatar

Level 2

Hi Have servlet which using querybuilder refrence. When i am writing Junit for that servlet and mocking of querybuilder is not working. I am getting null value for Querybuilder while running the junit .

 

package com.sample.core.servlets;

import static org.apache.sling.api.servlets.ServletResolverConstants.SLING_SERVLET_METHODS;
import static org.apache.sling.api.servlets.ServletResolverConstants.SLING_SERVLET_PATHS;

import java.io.IOException;

 

import java.util.*;
import javax.servlet.Servlet;
import javax.servlet.ServletException;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.json.JSONException;
import org.json.JSONObject;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.search.PredicateGroup;
import com.day.cq.search.Query;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.SearchResult;

import javax.jcr.Session;

 

@component(
service = { Servlet.class },
property = {
Constants.SERVICE_DESCRIPTION + "= Custom Asset Servlet ",
SLING_SERVLET_PATHS + "=/bin/test/customcreateassetservlet",
SLING_SERVLET_METHODS + "=" + HttpConstants.METHOD_POST
})
public class CustomCreateAssetServlet extends SlingAllMethodsServlet {
private static final long serialVersionUID = 4480344238141080952L;
private static final Logger log = LoggerFactory.getLogger(CustomCreateAssetServlet.class);

protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
try {
String assetsValue =request.getParameter("assetList");
log.info("assetsValue:"+assetsValue);
List<String> duplicateassetList = new ArrayList<String>();

List<String> assetList = new ArrayList<String>();
int length = 0;

String assets[] =assetsValue.split(",");

if(assets !=null && assets.length>0) {
for(int i=0; i<assets.length; i++) {
String assetName =assets[i];
assetList.add(assetName.substring(0, assetName.lastIndexOf(".")));
}
}

ResourceResolver resourceResolver = request.getResourceResolver();
QueryBuilder queryBuilder = resourceResolver.adaptTo(QueryBuilder.class);
HashMap<String, String> queryMap = new HashMap<String, String>();
queryMap.put("type", "dam:Asset");
queryMap.put("property", "@jcr:content/metadata/dam:scene7Name");
if(assetList !=null && assetList.size()>0) {
for(int i=0;i<assetList.size(); i++) {
queryMap.put("property."+i+1+"_value", assetList.get(i));
}
}

queryMap.put("orderby", "path");
queryMap.put("p.limit", "-1");
PredicateGroup predicate = PredicateGroup.create(queryMap);
Query query = queryBuilder.createQuery(predicate, resourceResolver.adaptTo(Session.class));
SearchResult searchResults = query.getResult();
length = searchResults.getHits().size();
for (int i = 0; i < length; i++) {
Resource resource = searchResults.getHits().get(i).getResource();
String resourcePath = resource.getPath();
duplicateassetList.add(resourcePath);
log.info("resourcePath:"+resourcePath);
}

JSONObject jsonobject = new JSONObject();
jsonobject.put("duplicateAssets", duplicateassetList);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(jsonobject.toString());


}catch (JSONException exceptionObject) {
log.error("Could not formulate JSON response");
response.setStatus(SlingHttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.getWriter().write("ERROR");
} catch (Exception e) {
log.error("Exception Occured" + e.getMessage());
response.setStatus(SlingHttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.getWriter().write("ERROR");
}
}

}

 

 

Junit for above Class:

 

ckage com.sample.core.servlets;

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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.jcr.Session;
import javax.servlet.http.HttpServletResponse;

import org.apache.sling.api.resource.ResourceResolver;
import org.json.JSONObject;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import com.day.cq.search.PredicateGroup;
import com.day.cq.search.Query;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.Hit;
import com.day.cq.search.result.SearchResult;

import io.wcm.testing.mock.aem.junit5.AemContext;
import io.wcm.testing.mock.aem.junit5.AemContextExtension;

@ExtendWith(AemContextExtension.class)
@displayname("Create Asset Servlet Test Cases")
public class CustomCreateAssetServletTest {

private final AemContext context = new AemContext();

@InjectMocks
CustomCreateAssetServlet customCreateAssetServlet = new CustomCreateAssetServlet();

@Mock
private ResourceResolver resourceResolver;

@Mock
private QueryBuilder queryBuilder;

@Mock
private PredicateGroup predicate;

@Mock
private Session session ;

@Mock
private Query query;

String assetsValue ="homelogo.png,Sample_Logo_portal.png,";

HashMap<String, String> queryMap;

JSONObject jsonObject = new JSONObject();


@BeforeEach
void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
queryMap = new HashMap<String, String>();
queryMap.put("type", "dam:Asset");
queryMap.put("property", "@jcr:content/metadata/dam:scene7Name");
queryMap.put("property.1_value", "homelogo");
queryMap.put("orderby", "path");
queryMap.put("p.limit", "-1");
}

@test
@displayname("Do Post with No Param")
void test_with_no_param() throws Exception {
Map<String, Object> parameterMap = new HashMap<>();
parameterMap.put("", "");
context.request().setParameterMap(parameterMap);
customCreateAssetServlet.doPost(context.request(), context.response());
assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, context.response().getStatus());
}

@test
@displayname("Do Post with Blank Path Param")
void test_with_blank_path_param() throws Exception {
Map<String, Object> parameterMap = new HashMap<>();
parameterMap.put("assetList", "");
context.request().setParameterMap(parameterMap);
customCreateAssetServlet.doPost(context.request(), context.response());
assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, context.response().getStatus());
}

@test
@displayname("Do Post with Asset List Param With All Attributes")
void test_with_asset_list_all_param() throws Exception {
Map<String, Object> parameterMap = new HashMap<>();
parameterMap.put("assetList", assetsValue);
context.request().setParameterMap(parameterMap);
when(resourceResolver.adaptTo(QueryBuilder.class)).thenReturn(queryBuilder);
when(resourceResolver.adaptTo(Session.class)).thenReturn(session);

// Session session = mock(Session.class);
// Query query = mock(Query.class);
when(queryBuilder.createQuery(Mockito.any(PredicateGroup.class), Mockito.eq(session))).thenReturn(query);
List<Hit> listHits = new ArrayList<>();
Hit hit = mock(Hit.class);
listHits.add(hit);
SearchResult searchResults = mock(SearchResult.class);


when(query.getResult()).thenReturn(searchResults);
when(searchResults.getHits()).thenReturn(listHits);
when(hit.getPath()).thenReturn("/content/dam/home/logo/homelogo.png");
customCreateAssetServlet.doPost(context.request(), context.response());
// JSONObject responseObject = new JSONObject(context.response());
// JSONObject assetsReponseJSON = new JSONObject(responseObject.getString("outputAsString").toString());
assertEquals(HttpServletResponse.SC_OK, context.response().getStatus());
// assertEquals(responseObject.get("duplicateAssets").toString(),"[\"/content/dam/home/logo/homelogo.png\"]");

}

}

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

Hi @bikash_kumar306,

As QueryBuilder can be adapted from ResourceResolver object, we can make use of registerAdapter method from AemContext as below

 

 

@Mock // This is from org.mockito.Mock;
private QueryBuilder queryBuilder;
private final AemContext aemContext = new AemContext(ResourceResolverType.JCR_MOCK);
aemContext.registerAdapter(ResourceResolver.class, QueryBuilder.class, queryBuilder);

 

 

Sample Test class structure for reference:

 

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.lenient;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.jcr.Session;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;

import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.testing.mock.sling.ResourceResolverType;
import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletRequest;
import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletResponse;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import com.day.cq.search.PredicateGroup;
import com.day.cq.search.Query;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.SearchResult;

import io.wcm.testing.mock.aem.junit5.AemContext;
import io.wcm.testing.mock.aem.junit5.AemContextExtension;

@ExtendWith({ AemContextExtension.class, MockitoExtension.class })
class CustomCreateAssetServletTest {

	private final AemContext aemContext = new AemContext(ResourceResolverType.JCR_MOCK);

	@Mock
	private QueryBuilder queryBuilder;

	@Mock
	private Query query;

	@Mock
	private SearchResult searchResult;

	private List<Resource> queryResults = new ArrayList<>(); // Populate this collection with actual results/test assets, to be checked in response JSON String

	@BeforeEach
	void setUp() throws Exception {
		/* Query Builder is adapted from Resource Resolver */
		aemContext.registerAdapter(ResourceResolver.class, QueryBuilder.class, queryBuilder);
		lenient().when(queryBuilder.createQuery(any(PredicateGroup.class), any(Session.class))).thenReturn(query);
		lenient().when(query.getResult()).thenReturn(searchResult);
		lenient().when(searchResult.getResources()).thenReturn(queryResults.iterator()); // test content/result is returned, can add further dummy implementation based on the actual code statements
	}

	@Test
	void testDoPostSlingHttpServletRequestSlingHttpServletResponse() throws ServletException, IOException {
		/* Request from Context */
		MockSlingHttpServletRequest mockRequest = aemContext.request();
		/* Response from Context */
		MockSlingHttpServletResponse mockResponse = aemContext.response();
		/* Instantiate Servlet under test */
		CustomCreateAssetServlet servletToTest = new CustomCreateAssetServlet();
		/* Invoke method under test */
		servletToTest.doPost(mockRequest, mockResponse);

		/* Assert Response status */
		assertEquals(HttpServletResponse.SC_OK, mockResponse.getStatus());

		/* Assert Response String */
		assertTrue(mockResponse.getOutputAsString().contains("")); // Amend this assertion per the way you set the test content

	}

}

 

View solution in original post

9 Replies

Avatar

Level 3

Hi @bikash_kumar306 

 

Have you tried not mocking the resourceResolver because AEM context object provides you resourceResolver and it should adaptTo queryBuilder API by default. Try to debug with a break point in your servlet class and make sure resourceResolver is injected correctly.

Avatar

Level 2
Hi Kalyan, I tried that but still it's was not working.

Avatar

Level 3
@bikah_kumar306 Not pretty sure about the issue here. But can you try to use JCR mock seems like you are using resourceResolver mock which is default. Try to set this and run the test case AemContext context = new AemContext(ResourceResolverType.JCR_MOCK);

Avatar

Community Advisor

@bikash_kumar306 
Try using PowerMockito or Prepare QueryBuilder class for mock.
long back using mockStatic(QueryBuilder.class) worked for me.


Avatar

Correct answer by
Community Advisor

Hi @bikash_kumar306,

As QueryBuilder can be adapted from ResourceResolver object, we can make use of registerAdapter method from AemContext as below

 

 

@Mock // This is from org.mockito.Mock;
private QueryBuilder queryBuilder;
private final AemContext aemContext = new AemContext(ResourceResolverType.JCR_MOCK);
aemContext.registerAdapter(ResourceResolver.class, QueryBuilder.class, queryBuilder);

 

 

Sample Test class structure for reference:

 

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.lenient;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.jcr.Session;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;

import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.testing.mock.sling.ResourceResolverType;
import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletRequest;
import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletResponse;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import com.day.cq.search.PredicateGroup;
import com.day.cq.search.Query;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.SearchResult;

import io.wcm.testing.mock.aem.junit5.AemContext;
import io.wcm.testing.mock.aem.junit5.AemContextExtension;

@ExtendWith({ AemContextExtension.class, MockitoExtension.class })
class CustomCreateAssetServletTest {

	private final AemContext aemContext = new AemContext(ResourceResolverType.JCR_MOCK);

	@Mock
	private QueryBuilder queryBuilder;

	@Mock
	private Query query;

	@Mock
	private SearchResult searchResult;

	private List<Resource> queryResults = new ArrayList<>(); // Populate this collection with actual results/test assets, to be checked in response JSON String

	@BeforeEach
	void setUp() throws Exception {
		/* Query Builder is adapted from Resource Resolver */
		aemContext.registerAdapter(ResourceResolver.class, QueryBuilder.class, queryBuilder);
		lenient().when(queryBuilder.createQuery(any(PredicateGroup.class), any(Session.class))).thenReturn(query);
		lenient().when(query.getResult()).thenReturn(searchResult);
		lenient().when(searchResult.getResources()).thenReturn(queryResults.iterator()); // test content/result is returned, can add further dummy implementation based on the actual code statements
	}

	@Test
	void testDoPostSlingHttpServletRequestSlingHttpServletResponse() throws ServletException, IOException {
		/* Request from Context */
		MockSlingHttpServletRequest mockRequest = aemContext.request();
		/* Response from Context */
		MockSlingHttpServletResponse mockResponse = aemContext.response();
		/* Instantiate Servlet under test */
		CustomCreateAssetServlet servletToTest = new CustomCreateAssetServlet();
		/* Invoke method under test */
		servletToTest.doPost(mockRequest, mockResponse);

		/* Assert Response status */
		assertEquals(HttpServletResponse.SC_OK, mockResponse.getStatus());

		/* Assert Response String */
		assertTrue(mockResponse.getOutputAsString().contains("")); // Amend this assertion per the way you set the test content

	}

}

 

Avatar

Level 9

Vijayalakshmi_S - Thank you much for the code snippet. It helped me to solve querybuilder mock issue

Avatar

Level 9

Vijayalakshmi_S - The below line did the magic. 

 

		aemContext.registerAdapter(ResourceResolver.class, QueryBuilder.class, queryBuilder);

 

I was getting queryBuilder as null and I spent almost a day to debug this issue. I double check all mock and everything but issue did not solve. After adding this line solved the issue. How do you know this? Is there any official documention ? I tried to see in https://wcm.io/testing/aem-mock/usage.html but there is method found "registerAdapter". 

 

Could you please tell me where and how do we come to all these api details ?