JUnit 4: 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 utilising 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.

Technologies here used are:

  • 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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());

    }
}
More…
Click here to view more examples of AEM JUnit 4 Unit Test Examples.

Hello, I am an enthusiastic Adobe Community Advisor and a seasoned Lead AEM Developer. I am currently serving as an AEM Technical Lead at MNPDigital.ca, bringing over a decade of extensive web engineering experience and more than eight years of practical AEM experience to the table. My goal is to give back to the AEM Full Stack Development community by sharing my wealth of knowledge with others. You can connect with me on LinkedIn.

One thought on “JUnit 4: AEM Sling Models Unit Test Constructor Injection Example

Leave a Reply

Your email address will not be published. Required fields are marked *


Back To Top