December 28, 2020
Estimated Post Reading Time ~

AEM Sling Servlet Unit Test Example Using wcm.io AEM Mocks, Servlet by Resource Type

This article will demonstrate how to write AEM Unit tests for @SlingServletResourceTypes (OSGi DS 1.4 (R7) component property type annotations) using the Junit4 testing framework. With developers being more visual, the source code is posted below.

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:


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.