Environment:
AEM project archetype 19 (link)
Mockito 2.27.0 (link)
AEM Mocks JUnit 4 2.7.2 (link)
This example uses the AEM project archetype 19 to generate a new AEM project, Junit 4 will be used as the testing framework, Mockito 2.27.0 will be used as the mocking framework, and AEM Mocks will be used to mock AEM objects and AEM API.
What’s really great about the latest versions of AEM mocks, is that the setup is very minimal. After spinning up a new AEM project from the AEM project archetype 19, you simply need to include the AEM Mocks dependency, and you are ready to go!
Using OSGI R7 annotations for your AEM project requires some additional dependencies.
Test Framework Dependencies
// pom.xml
<!-- Maven Surefire Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20</version>
<configuration>
<junitArtifactName>junit:junit:4</junitArtifactName>
</configuration>
</plugin>
...
<dependencies>
...
<dependency>
<groupId>io.wcm</groupId>
<artifactId>io.wcm.testing.aem-mock</artifactId>
<version>2.7.2</version>
<scope>test</scope>
</dependency>
...
</dependencies>
// core/pom.xml
<dependencies>
...
<dependency>
<groupId>io.wcm</groupId>
<artifactId>io.wcm.testing.aem-mock</artifactId>
</dependency>
...
</dependencies>
Sling Servlet Resource Types Class : SlingServletResourceTypes.class
package com.sourcedcode.core.servlets;
import com.day.cq.wcm.api.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
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.SlingSafeMethodsServlet;
import org.apache.sling.servlets.annotations.SlingServletResourceTypes;
import org.osgi.service.component.annotations.Component;
import javax.servlet.Servlet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import static com.day.crx.packaging.JSONResponse.APPLICATION_JSON_UTF8;
import static org.apache.sling.api.servlets.HttpConstants.METHOD_GET;
/**
* A demonstration sling servlet resource type class to demonstrate unit testing.
* Appending ".example.json" on any resource will activate the doGet() method below, and return Json data.
* Json Data returned is data from the immediate children of the "/content/we-retail', parent resource node.
*/
@Component(service = Servlet.class)
@SlingServletResourceTypes(
resourceTypes = "sling/servlet/default",
methods = METHOD_GET,
extensions = "json",
selectors = "example")
public class SlingServletResourceTypesExampleDS14Servlet extends SlingSafeMethodsServlet {
@Override
protected void doGet(SlingHttpServletRequest req, SlingHttpServletResponse res) throws IOException {
res.setContentType(APPLICATION_JSON_UTF8);
res.setStatus(SlingHttpServletResponse.SC_OK);
List<PageItem> pageItems = getPageItems(req);
String json = new ObjectMapper().writeValueAsString(pageItems);
res.getWriter().write(json);
}
private List<PageItem> getPageItems(SlingHttpServletRequest req) {
List<PageItem> pageItems = new ArrayList<>();
ResourceResolver resolver = req.getResourceResolver();
Resource weRetail = resolver.getResource("/content/we-retail");
if (weRetail != null) {
Iterator<Resource> it = weRetail.listChildren();
while (it.hasNext()) {
Resource resource = it.next();
if (resource.getResourceType().equalsIgnoreCase(com.day.cq.wcm.api.NameConstants.NT_PAGE)) {
Page page = resource.adaptTo(Page.class);
if (page != null) {
pageItems.add((new PageItem(page.getTitle(), resource.getPath())));
}
}
}
}
return pageItems;
}
/**
* Inner class PageItem, for creating PageItem objects.
*/
public class PageItem {
private String pageTitle;
private String pagePath;
PageItem(String pageTitle, String pagePath) {
this.pageTitle = pageTitle;
this.pagePath = pagePath;
}
public String getPageTitle() {
return pageTitle;
}
public String getPagePath() {
return pagePath;
}
}
}
Results of the output from the working as expected SlingServletResourceTypesTest.class.
Sling Servlet Resource Types Test Class : SlingServletResourceTypesTest.class
package com.sourcedcode.core.servlets;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.wcm.testing.mock.aem.junit.AemContext;
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.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.io.IOException;
import static com.day.crx.packaging.JSONResponse.APPLICATION_JSON_UTF8;
import static junitx.framework.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@RunWith(MockitoJUnitRunner.class)
public class SlingServletResourceTypesExampleDS14ServletTest {
@Rule
public final AemContext context = new AemContext(ResourceResolverType.JCR_MOCK);
@Mock
private MockSlingHttpServletRequest req;
@Mock
private MockSlingHttpServletResponse res;
@InjectMocks
private SlingServletResourceTypesExampleDS14Servlet underTest;
@Before
public void setup() {
underTest = new SlingServletResourceTypesExampleDS14Servlet();
req = context.request();
res = context.response();
}
@Test
public void doGet_shouldReturnHeaderAsExpected() throws IOException {
underTest.doGet(req, res);
assertEquals(res.getContentType(), APPLICATION_JSON_UTF8);
}
@Test
public void doGet_shouldReturnPageItemListJsonAsExpected_0() throws IOException {
underTest.doGet(req, res);
String jsonString = res.getOutputAsString();
ObjectMapper mapper = new ObjectMapper();
JsonNode actualObj = mapper.readTree(jsonString);
assertEquals(0, actualObj.size());
}
@Test
public void doGet_shouldReturnPageItemJsonAsExpected_properties_values() throws IOException {
createPagesInJcrMock();
underTest.doGet(req, res);
String jsonString = res.getOutputAsString();
ObjectMapper mapper = new ObjectMapper();
JsonNode actualObj = mapper.readTree(jsonString);
JsonNode firstItem = actualObj.get(0);
assertTrue(firstItem.has("pageTitle"));
assertTrue(firstItem.has("pagePath"));
assertEquals( "United states", firstItem.get("pageTitle").textValue());
assertEquals("/content/we-retail/us", firstItem.get("pagePath").textValue());
}
/**
* Test helper method to create 3 pages in the on-memory JCR Mock instance.
*/
private void createPagesInJcrMock() {
context.create().page("/content/we-retail", "/", "We Retail");
context.create().page("/content/we-retail/us", "/", "United states");
context.create().page("/content/we-retail/ca", "/", "Canada");
}
}
NOTES:
- Though the endpoint path is ugly (because it consists of extensions, selectors, and etc…), it is recommended to register servlet by resource types rather than by path (click here to learn why @SlingServletPaths, register by path, are not recommended).
- If there is a requirement to mask or to sugarcoat the ugly URI paths, a common strategy used is the Apache webserver. Click here to learn to sugar coat registered AEM servlet scripts and paths endpoint.
No comments:
Post a Comment
If you have any doubts or questions, please let us know.