December 28, 2020
Estimated Post Reading Time ~

AEM Sling Models Unit Test Constructor Injection Example

In this example, we will take a look at how we can mock Sling Model Constructor Injection dependencies for a JUnit 4 Unit test.

Scenario:
The Sling Model must expose either the PROD_URL or the DEAFULT_URL endpoint based on the run mode or request parameters; this is the requirement. The example below will demonstrate the implementation of logic utilizing Sling Model Constructor injection, show Unit test examples, and how mocked dependencies can be Sling Model Constructor injected during the test phase. This completes the example.

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 objects.

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!

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 Model Test Class : ConstructorInjection.class
package com.sourcedcode.core.models;

import com.adobe.cq.export.json.ExporterConstants;
import lombok.Getter;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Exporter;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
import org.apache.sling.models.annotations.injectorspecific.SlingObject;
import org.apache.sling.settings.SlingSettingsService;

import javax.inject.Inject;
import javax.inject.Named;

import static org.apache.commons.lang3.StringUtils.EMPTY;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;

@Model(adaptables = {SlingHttpServletRequest.class, Resource.class}, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION)
public class ConstructorInjection {

protected static final String API_URL_PROD = "https://api.sourcedcode.com/v1/constructors";
protected static final String API_URL_DEFAULT = "https://uat-api.sourcedcode.com/v1/constructors";

@Getter
private String apiUrl = EMPTY;

@Inject
public ConstructorInjection(@OSGiService @Named("slingSettingsService") final SlingSettingsService slingSettingsService,
@SlingObject @Named("slingHttpServletRequest") final SlingHttpServletRequest request) {
boolean isProd = slingSettingsService.getRunModes().contains("prod");
boolean isParamProd = isNotEmpty(request.getParameter("prod")) && request.getParameter("prod").equals("true");
if (isProd || isParamProd) {
apiUrl = API_URL_PROD;
} else {
apiUrl = API_URL_DEFAULT;
}
}
}


Sling Model Test Class : ConstructorInjectionTest.class
package com.sourcedcode.core.models;

import io.wcm.testing.mock.aem.junit.AemContext;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.settings.SlingSettingsService;
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 java.util.Collections;

import static org.junit.Assert.assertEquals;
import static uk.co.whitbread.wlrestaurants.core.models.ConstructorInjection.API_URL_DEFAULT;
import static uk.co.whitbread.wlrestaurants.core.models.ConstructorInjection.API_URL_PROD;

@RunWith(MockitoJUnitRunner.class)
public class ConstructorInjectionTest {

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

@Mock
private SlingSettingsService slingSettingsService;

@Mock
SlingHttpServletRequest request;

@InjectMocks
private ConstructorInjection underTest;

@Test
public void apiUrl_should_return_PROD_url_when_runmode_prod() {
context.runMode("prod");
underTest = context.request().adaptTo(ConstructorInjection.class);
assert underTest != null;
assertEquals(API_URL_PROD, underTest.getApiUrl());
}

@Test
public void apiUrl_should_return_DEFAULT_url_when_runmode_not_prod() {
context.runMode("staging");
underTest = context.request().adaptTo(ConstructorInjection.class);
assert underTest != null;
assertEquals(API_URL_DEFAULT, underTest.getApiUrl());
}

@Test
public void apiUrl_should_return_PROD_url_when_param_prod_equals_true() {
context.request().setParameterMap(Collections.singletonMap("prod", "true"));
underTest = context.request().adaptTo(ConstructorInjection.class);
assert underTest != null;
assertEquals(API_URL_PROD, underTest.getApiUrl());
}

@Test
public void apiUrl_should_return_DEFAULT_url_when_param_prod_equals_not_true() {
context.request().setParameterMap(Collections.singletonMap("prod", "test"));
underTest = context.request().adaptTo(ConstructorInjection.class);
assert underTest != null;
assertEquals(API_URL_DEFAULT, underTest.getApiUrl());

}
}



By aem4beginner

No comments:

Post a Comment

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