Expand my Community achievements bar.

Don’t miss the AEM Skill Exchange in SF on Nov 14—hear from industry leaders, learn best practices, and enhance your AEM strategy with practical tips.
SOLVED

AEM servlet JUNIT 5 help

Avatar

Level 3

Hi Team,

 

I am trying to write JUNIT5 test code for below servlet. I am stuck and not  able to proceed further. When I debug Test Class and it takes me to doGet Method of servlet,It always gives me NULL pointer Exception for RestAPIConfigurations service(). Highlighted in Blue Color.

Below are servlet and JUNIT code.

Any help will be  appreciated.

SERVLET CODE:

@component(service = Servlet.class, property = {
Constants.SERVICE_ID + "=Dynamic DataSource Servlet",
SLING_SERVLET_METHODS + "=" + HttpConstants.METHOD_GET,
SLING_SERVLET_RESOURCE_TYPES + "=mysite/product/details"
})
public class HubSourceServlet extends SlingSafeMethodsServlet {
private static final String TAG = HubSourceServlet.class.getSimpleName();
private static final Logger LOGGER = LoggerFactory.getLogger(HubSourceServlet.class);

@reference
RestAPIConfigurations restAPIConfigurations;

@Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) {
try {
ResourceResolver resourceResolver = request.getResourceResolver();
String domainName = restAPIConfigurations.getDomain();
LOGGER.debug(TAG, domainName);

Resource currentResource = request.getResource();
String selector = Objects.requireNonNull(currentResource.getChild("datasource")).getValueMap().get("selector", String.class);
String jsonData = StringUtils.EMPTY;
boolean fifthLevelFlag = true;
if(null != selector && StringUtils.equals("news", selector)){
fifthLevelFlag = false;
}
if(null != selector && StringUtils.equals("articles",selector)){
LOGGER.info("selector in HubSourceServlet is :",selector);
jsonData = getData(domainName+"/api/v1/REST/articles-groups");
}
else {

jsonData = getData(domainName+"/api/v1/REST/news-groups");
}

JSONArray data = new JSONArray(jsonData);

DataSource ds = new SimpleDataSource(getValueMapResource(data, resourceResolver));

request.setAttribute(DataSource.class.getName(), ds);
} catch (IOException | JSONException e) {
}
}

public String getData(String path) throws IOException {

TrustManager[] trustAll= new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}

public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}

public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
SSLContext sc = null;
try {
sc = SSLContext.getInstance("SSL");
sc.init(null, trustAll, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}

InputStream is = null;
String content = null;
try {

LOGGER.info("In HubSourceServlet getData url: {}", path);
URL urlObj = new URL(path);
String auth = restAPIConfigurations.getUserName() + ":" + restAPIConfigurations.getPassName();
byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes(StandardCharsets.UTF_8));
String authHeaderValue = "Basic " + new String(encodedAuth);
HttpURLConnection httpURLConnection = (HttpURLConnection) urlObj.openConnection();
httpURLConnection.setRequestProperty("Authorization", authHeaderValue);

httpURLConnection.setRequestMethod("GET");
is = httpURLConnection.getInputStream();
content = IOUtils.toString(is, StandardCharsets.UTF_8);
LOGGER.info("In HubSourceServlet getData content: {}", content);
} finally {
IOUtils.closeQuietly(is);
}

return content;
}
public void setrestAPIConfigurations(restAPIConfigurations restAPIConfigurations) {
this.restAPIConfigurations = restAPIConfigurations;
}
}

 

JUNIT CLASS:

@ExtendWith(AemContextExtension.class)
@ExtendWith(MockitoExtension.class)
class HubSourceServletTest {

private final AemContext context = AppAemContext.newAemContext();

private static HubSourceServlet HubSourceServlet;

private static JSONArray data;

private static String domainName;

@Mock
private static RestAPIConfigurations restAPIConfigurations;

@Mock
private static Resource currentResource;

@Mock
private ResourceResolver resourceResolver;

@BeforeAll
public static void setUp() {
HubSourceServlet = new HubSourceServlet();

}
@BeforeEach
public void setUpBefore() {
when(restAPIConfigurations.getDomain()).thenReturn("mydomain");
}

@test
void doGet() {
SlingHttpServletRequest request = context.request();
SlingHttpServletResponse response = context.response();
HubSourceServlet.doGet(request,response);

assert (true);
}
}

 

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

Try this in your setup method

context.registerService(RestAPIConfigurations.class, restAPIConfigurations);



View solution in original post

3 Replies

Avatar

Correct answer by
Community Advisor

Try this in your setup method

context.registerService(RestAPIConfigurations.class, restAPIConfigurations);



Avatar

Level 6

Hi @arvindpandey , Please refer below working code:

 

//---RestAPIConfigurations.java---
public interface RestAPIConfigurations {
    String getDomain();
}

//---RestAPIConfigurationsImpl.java---
@Component(immediate = true, service = RestAPIConfigurations.class)
@Designate(ocd = RestAPIConfigurationsImpl.Configs.class)
public class RestAPIConfigurationsImpl implements RestAPIConfigurations {

    private String domainName;

    @Activate
    @Modified
    public void activate(Configs configs) {
        domainName = configs.domainName();
    }


    @ObjectClassDefinition(name = "keys", description = "keys")
    public @interface Configs {
        @AttributeDefinition(name = "Url", description = "Url")
        String domainName();
    }

    @Override
    public String getDomain(){return domainName;}

}

//---HubSourceServlet.java---
@Component(service = Servlet.class, property = {
        Constants.SERVICE_ID + "=Dynamic DataSource Servlet",
        SLING_SERVLET_METHODS + "=" + HttpConstants.METHOD_GET,
        SLING_SERVLET_RESOURCE_TYPES + "=mysite/product/details"
})
public class HubSourceServlet extends SlingSafeMethodsServlet {
    private static final String TAG = HubSourceServlet.class.getSimpleName();
    private static final Logger LOGGER = LoggerFactory.getLogger(HubSourceServlet.class);

    @Reference
    RestAPIConfigurations restAPIConfigurations;

    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException {
        String domainName = restAPIConfigurations.getDomain();
        request.setAttribute(domainName,String.class);
    }
}

//---HubSourceServletTest.java---
@ExtendWith(MockitoExtension.class)
class HubSourceServletTest {

    @InjectMocks
    HubSourceServlet hubSourceServlet;

    @Mock
    SlingHttpServletRequest slingRequest;

    @Mock
    SlingHttpServletResponse slingResponse;

    @Mock
    RestAPIConfigurationsImpl.Configs restAPIConfigurations;
    @Mock
    private RestAPIConfigurationsImpl restAPIConfigurationsImpl;

    @Test
    void doGet() {
        when(restAPIConfigurationsImpl.getDomain()).thenReturn("test");
        assertEquals("test",restAPIConfigurationsImpl.getDomain());
    }
}

 

 

Avatar

Level 4

Hi @arvindpandey 

From what I can see, the issue is that the restAPIConfigurations service is not being injected into your servlet instance in the test class.

In your test class, you have mocked the RestAPIConfigurations service, but you haven't injected it into the HubSourceServlet instance.

Here's how you can fix it:

@ExtendWith(AemContextExtension.class)
@ExtendWith(MockitoExtension.class)
class HubSourceServletTest {

private final AemContext context = AppAemContext.newAemContext();

private static HubSourceServlet hubSourceServlet;

private static JSONArray data;

private static String domainName;

@Mock
private static RestAPIConfigurations restAPIConfigurations;

@Mock
private static Resource currentResource;

@Mock
private static ResourceResolver resourceResolver;

@BeforeAll
public static void setUp() {
hubSourceServlet = new HubSourceServlet();
hubSourceServlet.setrestAPIConfigurations(restAPIConfigurations); // inject the mock service
}

@BeforeEach
public void setUpBefore() {
when(restAPIConfigurations.getDomain()).thenReturn("mydomain");
}

@Test
void doGet() {
SlingHttpServletRequest request = context.request();
SlingHttpServletResponse response = context.response();
hubSourceServlet.doGet(request,response);

assert (true);
}
}

By calling hubSourceServlet.setrestAPIConfigurations(restAPIConfigurations) in the @BeforeAll method, you're injecting the mocked RestAPIConfigurations service into the HubSourceServlet instance.

This should fix the NullPointerException you're seeing when you debug the test class and it takes you to the doGet method of the servlet.