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!
Views
Replies
Total Likes
try this :
Resource resource = context.resourceResolver().getResource("/content/sample/en");
reference : https://wcm.io/testing/aem-mock/usage.html
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);
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");
}
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.
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.
Views
Likes
Replies