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

junit with AemContextExtension

Avatar

Level 3

Hi I am trying to write junit using aem context for the first time, below is my sample sling model class.

 

@Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class HeadlineModel {
private static final Logger LOGGER = LoggerFactory.getLogger(HeadlineModel.class);
@ValueMapValue
@Optional
private String size;
@ValueMapValue
@Optional
private String alignment;
@ValueMapValue
@Optional
private String headlinetext;
@ValueMapValue
@Optional
private String scheme;

public String getSize() {
return size;
}

public String getAlignment() {
return alignment;
}

public String getHeadlinetext() {
return headlinetext;
}

public String getScheme() {
return scheme;
}
}

Could someone give example to mock the above getters with latest way of using aemcontext

 

1 Accepted Solution

Avatar

Correct answer by
Employee Advisor

I have given an example how to unittest a sling model at https://cqdump.wordpress.com/2019/01/17/writing-unittests-for-aem-part-3-mocking-resources/, it should answer your questions.

 

Jörg

View solution in original post

3 Replies

Avatar

Community Advisor

@srikanthg212933,

Sure. There are really good resources online that should help you get started. Try here https://sourcedcode.com/category/aem/junit4

Original Blog: https://sourcedcode.com/aem-sling-models-unit-test-junit-4-with-examples

 

Header.class

package com.sourcedcode.core.models;

import com.day.cq.wcm.api.Page;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.ChildResource;
import org.apache.sling.models.annotations.injectorspecific.ScriptVariable;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

@Model(adaptables = Resource.class,
        resourceType = Header.RESOURCE_TYPE,
        defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class Header {

    protected static final String RESOURCE_TYPE = "sourcedcode/components/structure/header";

    @ValueMapValue
    private String contactUsPath;

    @ScriptVariable(name="currentPage")
    private Page currentPage;

    @ChildResource(name="link")
    Resource childResource;

    @SlingObject
    private ResourceResolver resolver;

    private String contactUsPageSecretChar;

    @PostConstruct
    public void init() {
        setContactUsPageSecretChar();
    }

    private void setContactUsPageSecretChar() {
        Resource resource = resolver.getResource(contactUsPath);
        if (resource != null) {
            Page contactUsPage = resource.adaptTo(Page.class);
            contactUsPageSecretChar = contactUsPage.getTitle();
        }
    }

    public String getContactUsPageSecretChar() {
        return contactUsPageSecretChar.substring(contactUsPageSecretChar.length() - 1);
    }

    // demo of testing the @ScriptVariable("currentPage") annotation
    public String getPageTitle() {
        return currentPage.getPageTitle();
    }

    // demo of testing the @ChildResource annotation
    public String getChildLinkPropFlag() {
        return childResource.getValueMap().get("flag", "");
    }
}

HeaderTest.class

package com.sourcedcode.core.models;

import com.adobe.cq.commerce.common.ValueMapDecorator;
import com.day.cq.wcm.api.Page;
import com.google.common.collect.ImmutableMap;
import io.wcm.testing.mock.aem.junit.AemContext;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.testing.mock.sling.ResourceResolverType;
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 static junitx.framework.Assert.assertEquals;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class HeaderTest {

    @Rule
    public final AemContext context = new AemContext(ResourceResolverType.JCR_MOCK);

    // the context.resourceResolver() is auto injected by the AemContext, cannot be mocked.
    // ResourceResolver resolver;

    // mocking the global AEM object "currentPage".
    // variable does not need to match the variables in the underTest.class
    @Mock
    private Page currentPage;

    // injects all the mocks into the tested object.
    @InjectMocks
    private Header underTest;

    @Test
    public void itShouldReturnTheCorrectSecretCharWhenResourceExist() {
        // using the AEM context to create an AEM resource in the context, to set properties for the resource.
        // the resource path can be anything made up.
        Resource headerResourceContext = context.create().resource("/content/sourcedcode/home/jcr:content/header", new ValueMapDecorator(ImmutableMap.<String, Object> of(
                "contactUsPath", "/content/sourcedcode/contact",
                "anotherProperty", "example")));

        // create mock page, resolved by the resolver.
        context.create().page("/content/sourcedcode/contact", "", ImmutableMap.<String, Object>builder()
                .put("jcr:title", "Contact Us Page")
                .build());

        underTest = headerResourceContext.adaptTo(Header.class);
        assertEquals("e", underTest.getContactUsPageSecretChar());
    }

    @Test
    public void itShouldReturnTheCorrectCurrentPageTitle() {
        when(currentPage.getPageTitle()).thenReturn("Home Page");
        assertEquals("Home Page", underTest.getPageTitle());
    }

    @Test
    public void itShouldReturnTheCorrectChildLinkProperty() {
        context.build().resource("/content/sourcedcode/home/jcr:content/header")
                .siblingsMode()
                .resource("link", "flag", "newPage");
        underTest = context.resourceResolver().getResource("/content/sourcedcode/home/jcr:content/header").adaptTo(Header.class);
        assertEquals("newPage", underTest.getChildLinkPropFlag());
    }

}

Avatar

Correct answer by
Employee Advisor

I have given an example how to unittest a sling model at https://cqdump.wordpress.com/2019/01/17/writing-unittests-for-aem-part-3-mocking-resources/, it should answer your questions.

 

Jörg

Avatar

Community Advisor

Hi @srikanthg212933 ,

 

You can refer the sample hello world test class to achieve this.

@ExtendWith(AemContextExtension.class)
class HelloWorldModelTest {

private HelloWorldModel hello;

private Page page;
private Resource resource;

@BeforeEach
public void setup(AemContext context) throws Exception {

// prepare a page with a test resource
page = context.create().page("/content/mypage");
resource = context.create().resource(page, "hello",
"sling:resourceType", "myproject/components/content/helloworld");

// create sling model
hello = resource.adaptTo(HelloWorldModel.class);
}

@Test
void testGetMessage() throws Exception {
// some very basic junit tests
String msg = hello.getMessage();
assertNotNull(msg);
assertTrue(StringUtils.contains(msg, resource.getResourceType()));
assertTrue(StringUtils.contains(msg, page.getPath()));
}

}

 

Regards,

Santosh