Expand my Community achievements bar.

Radically easy to access on brand approved content for distribution and omnichannel performant delivery. AEM Assets Content Hub and Dynamic Media with OpenAPI capabilities is now GA.

@Inject annotation in AEM JUnit

Avatar

Level 2

Hi all,
I have many Sling Models and I need to create a JUnit test for them, but I'am not able to deal with the @inject  annotation.
Here a simple example:
Sling Model:

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.Model;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;

@Model(adaptables = {SlingHttpServletRequest.class}, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class SimpleModel {

protected final Logger logger = LoggerFactory.getLogger(getClass());

@Inject
protected Resource currentResource;

@Getter
private List<Resource> items;

@PostConstruct
protected void init() {
items = new ArrayList<>();
try {
Resource parsys = currentResource.getChild("parsys");
if (parsys != null) {
for(Resource child : parsys.getChildren()) {
items.add(child);
}
}
} catch (Exception ex) {
logger.error("Unexpected error: ", ex);
}
}

}

Test:

import io.wcm.testing.mock.aem.junit5.AemContext;
import io.wcm.testing.mock.aem.junit5.AemContextBuilder;
import io.wcm.testing.mock.aem.junit5.AemContextExtension;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.impl.injectors.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@ExtendWith({AemContextExtension.class, MockitoExtension.class})
class SimpleModelTest{

private AemContext context = new AemContext();
private SimpleModel simpleModel;

@BeforeEach
public void setup() throws Exception {
context.addModelsForClasses(SimpleModel.class);
context.load().json("SimpleModelTest.json", "/content/myproject/us");
currentResource = context.currentResource("/content/myproject/us/jcr:content/simple-component");
context.request().setResource(currentResource);
simpleModel = context.request().adaptTo(SimpleModel.class);
}

@Test
void testGetRowsItems() {
//Build expected result
Resource parsys = currentResource.getChild("parsys");
List<Resource> expectedResult = new ImmutableList.Builder<Resource>()
.add(parsys.getChild("item1"))
.add(parsys.getChild("item2"))
.build();

//Build actual result
List<Resource> actualResult = simpleModel.getItems();
//Check the actual result
assertEquals(expectedResult.size(), actualResult.size());
}

}

The actualResult.size() gives me 0 because the @inject currentResource is not "executed" (currentResource is null).

If I change the annotation from @inject to @SlingObject the test goes well but of course I want that my tests work with @inject annotation.
Could anyone help me?
Thanks!

4 Replies

Avatar

Employee Advisor

try this : 

Resource resource = context.resourceResolver().getResource("/content/sample/en");

 reference : https://wcm.io/testing/aem-mock/usage.html

 

Avatar

Level 2

Thank you for your reply, but it doesn't seem to work since I received the same result.
Below the code that I have tried:

context.load().json("SimpleModelTest.json", "/content/myproject/us");
currentResource = context.resourceResolver().getResource("/content/myproject/us/jcr:content/simple-component");
//Test 1
simpleModel
= context.request().adaptTo(SimpleModel.class);
//Test 2
simpleModel = currentResource.adaptTo(SimpleModel.class);

 

 

Avatar

Employee Advisor

I did a small setup. I am able to get the resource object

ExampleTest:

 

package com.adobe.aem.guides.wknd.core.models;

 

import org.apache.sling.api.resource.Resource;

import org.junit.jupiter.api.BeforeEach;

import org.junit.jupiter.api.Test;

import org.junit.jupiter.api.extension.ExtendWith;

 

import com.day.cq.wcm.api.Page;

 

import io.wcm.testing.mock.aem.junit5.AemContext;

import io.wcm.testing.mock.aem.junit5.AemContextExtension;

 

@ExtendWith(AemContextExtension.class)

public class ExampleTest {

 

  private final AemContext context = new AemContext();

 

  @BeforeEach

  public void setUp() throws Exception {

    context.load().json("/com/adobe/aem/guides/wknd/core/models/impl/sample-data.json", "/content/sample/en");

  }

 

  @test

  public void testSomething() {

    Resource resource = context.resourceResolver().getResource("/content/sample/en");

    Page page = resource.adaptTo(Page.class);

    // further testing

  }

 

}

 

sample-data.json:

 

{

  "jcr:primaryType": "cq:Page",

  "jcr:content": {

    "jcr:primaryType": "cq:PageContent",

    "jcr:title": "English",

    "cq:template": "/apps/sample/templates/homepage",

    "sling:resourceType": "sample/components/homepage",

    "jcr:createdBy": "admin",

    "jcr:created": "Thu Aug 07 2014 16:32:59 GMT+0200",

    "par": {

      "jcr:primaryType": "nt:unstructured",

      "sling:resourceType": "foundation/components/parsys",

      "colctrl": {

        "jcr:primaryType": "nt:unstructured",

        "layout": "2;cq-colctrl-lt0",

        "sling:resourceType": "foundation/components/parsys/colctrl"

      }

    }

  }

}

 

Attached screenshot for reference.

unnamed.jpeg

Avatar

Level 2

Thank you, but my problem is related on the adaptation of the Resource to "SimpleModel" in a test scenario.
In my SimpleModel, I perfom the injection of the currentResource via @inject annotation, but
when I try to test it, the currentResource injected is null and therefore my test fails (simpleModel = currentResource.adaptTo(SimpleModel.class); gives me an instance of SimpleModel with its currentResource instance variable to null).
If I change in SimpleModel from @inject annotation to @SlingObject annotation all works.
In other words, @inject seem to not work and I don't know if I need to mock some OsgiService on @BeforeEach phase or I have some missed dependency in my project.
Thank you a lot for you support.