Unit Testing ChildResource | Adobe Higher Education
Skip to main content
Mahedi_Sabuj
Community Advisor
Community Advisor
July 17, 2023
Risolto

Unit Testing ChildResource

  • July 17, 2023
  • 4 risposte
  • 2382 visualizzazioni

In Unit Test, @ChildResource annotation property always return null. Can anyone please guide me to resolve the issue?

Environment Details: AEM 6.5.16 and Java 11

CountryListImpl.java

 

@Model( adaptables = SlingHttpServletRequest.class, adapters = { CountryList.class }, resourceType = CountryListImpl.RESOURCE_TYPE, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL ) @Exporter( name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION ) public class CountryListImpl implements CountryList { protected static final String RESOURCE_TYPE = "aem-demo/components/country-list"; protected static final String COUNTRY_LANGUAGE_LIST = "countryItems"; @ValueMapValue @Named("title") String defaultLabel; @ChildResource(name = COUNTRY_LANGUAGE_LIST) List< CountryItem > countryList; public String getDefaultLabel() { return defaultLabel; } public List<CountryItem> getCountryList() { return countryList; } }

 

CountryItemImpl.java

 

@Model( adaptables = Resource.class, adapters = { CountryItem.class }, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL ) public class CountryItemImpl implements CountryItem { @ValueMapValue String country; @ValueMapValue String language; @ValueMapValue String link; public String getCountry() { return country; } public String getLanguage() { return language; } public String getLink() { return link; } }

 

CountryListImplTest.java

 

@ExtendWith(AemContextExtension.class) public class CountryListImplTest { private final AemContext ctx = new AemContext(ResourceResolverType.JCR_MOCK); private CountryList countryList; @BeforeEach public void setup() { ctx.load().json( "/com/aem/demo/core/components/internal/models/v1/country-list.json", "/content" ); ctx.currentResource("/content/country-list"); countryList = Objects.requireNonNull(ctx.getService(ModelFactory.class)) .createModel(ctx.request(), CountryListImpl.class); } public void getCountryListTest() { Assertions.assertNotNull(countryList); // countryList.getCountryList() --> ALWAYS RETURN NULL // Assertions.assertNotNull(countryList.getCountryList()); // Assertions.assertEquals( // 2, countryList.getCountryList().size() // ); } }

 

country-list.json

 

{ "country-list": { "jcr:primaryType": "nt:unstructured", "sling:resourceType": "awcm-demo/components/country-list", "title": "Select ...", "countryItems": { "jcr:primaryType": "nt:unstructured", "item0": { "jcr:primaryType": "nt:unstructured", "country": "Austria", "link": "/content/aem-demo/at/de", "language": "German" }, "item1": { "jcr:primaryType": "nt:unstructured", "country": "Canada", "link": "/content/aem-demo/ca/en", "language": "English" } } } }

 

Questo argomento è stato chiuso alle risposte.
Migliore risposta di Mahedi_Sabuj

I've identified a simplified solution, and I only need to implement two modifications.

1. CountryListImpl:  change adaptables to Resource.Class

@Model( adaptables = Resource.class, adapters = { CountryLinkButton.class }, resourceType = CountryLinkButtonImpl.RESOURCE_TYPE, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL ) @Exporter( name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION ) public class CountryLinkButtonImpl implements CountryLinkButton { ..... }

2. CountryListImplTest: Update createModel

createModel(ctx.request().getResource(), CountryListImpl.class);

Reference: https://medium.com/@veena.vikraman19/aem-junit-for-simple-aem-component-with-multifield-2326f61c8982 

4 risposte

ManviSharma
Adobe Employee
Adobe Employee
July 17, 2023

Hi,

 

In the given test case, the @ChildResource annotation may return null because the AEM context used for testing is not properly initialized to include the child resources from the JSON file. To resolve this issue, you can modify the test setup method as follows:

@BeforeEach
public void setup() {
ctx.load().json(
"/com/aem/demo/core/components/internal/models/v1/country-list.json",
"/content"
);

// Update the path to include the child resource
ctx.currentResource("/content/country-list/countryItems");

countryList = Objects.requireNonNull(ctx.getService(ModelFactory.class))
.createModel(ctx.request(), CountryListImpl.class);
}

 

-> By updating the path to include /countryItems, you ensure that the child resource is loaded correctly, and the @ChildResource annotation can populate the countryList property.

Please note that the JSON file and the AEM context setup should match the structure and resource paths in your project for the test to run successfully.

Mahedi_Sabuj
Community Advisor
Community Advisor
July 17, 2023

Hi @manvisharma, I updated the current resource to /content/country-list/countryItems but countryList.getCountryList() still NULL. Thanks.

Mahedi Sabuj
Nishant-Singh
Adobe Employee
Adobe Employee
July 17, 2023

You are using Model class with name (adaptor class name ) CountryList.class and in createModel you are using CountryListImpl.class  please correct  - 

 

 

 

 

countryList = Objects.requireNonNull(ctx.getService(ModelFactory.class)) .createModel(ctx.request(), CountryListImpl.class);

 

 

to 

 

 

countryList = Objects.requireNonNull(ctx.getService(ModelFactory.class)) .createModel(ctx.request(), CountryList.class);

 

 

 

Mahedi_Sabuj
Community Advisor
Community Advisor
July 17, 2023

Hi @nishant-singh, countryList is an object of CountryListImpl (not CountryItem), CountryItem will response ClassCastException.

Mahedi Sabuj
Nishant-Singh
Adobe Employee
Adobe Employee
July 17, 2023

you need to create object  by adapting method

countyList = aemContext.request().adaptTo(CountryList.class);

 

Sady_Rifat
Community Advisor
Community Advisor
July 17, 2023

Hi @mahedi_sabuj ,

Just checked your problem. You are using Sling Deligation Pattern, I have an article on how to write unit tests for this type of Sling Model: https://medium.com/@sadyrifat/aem-unit-test-case-for-sling-delegation-pattern-1f011b947fb3 

The way you are approaching is somehow wrong and you will get trouble on this.

 

By using this article your Unit test will be like this: 

 

 

private final AemContext context = new AemContextBuilder(ResourceResolverType.JCR_MOCK).plugin(CORE_COMPONENTS).build(); private CountryList countryList; @BeforeEach void init() { Resource pageResource = context.load().json("/com/aem-demo/core/internal/models/page.json", "/content/uk"); Page page = pageResource.getChild("en/product").adaptTo(Page.class); Map<String, Object> jsonObject = TestUtils.getJsonObject("/com/aem-demo/core/internal/models/country-list.json"); context.currentResource(context.create().resource(page, "countryList", jsonObject)); countryList = context.request().adaptTo(CountryListImpl.class); } @Test void countryList() { assertNotNull(countryList); }

 

And most importantly your json will be this,

 

{ "jcr:primaryType": "nt:unstructured", "sling:resourceType": "awc-demo/components/country-list", "title": "Select ...", "countryItems": { "jcr:primaryType": "nt:unstructured", "item0": { "jcr:primaryType": "nt:unstructured", "country": "Austria", "link": "/content/aem-demo/at/de", "language": "German" }, "item1": { "jcr:primaryType": "nt:unstructured", "country": "Canada", "link": "/content/aem-demo/ca/en", "language": "English" } } }

 

 

After running your code with this setup I am getting the clildresources.

Hope this helps you.

Mahedi_Sabuj
Community Advisor
Community Advisor
July 17, 2023

Hi @sady_rifat, Let me check your implementation, I will get back to you soon.

Mahedi Sabuj
Mahedi_Sabuj
Community Advisor
Mahedi_SabujCommunity AdvisorAutoreRisposta
Community Advisor
August 15, 2023

I've identified a simplified solution, and I only need to implement two modifications.

1. CountryListImpl:  change adaptables to Resource.Class

@Model( adaptables = Resource.class, adapters = { CountryLinkButton.class }, resourceType = CountryLinkButtonImpl.RESOURCE_TYPE, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL ) @Exporter( name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION ) public class CountryLinkButtonImpl implements CountryLinkButton { ..... }

2. CountryListImplTest: Update createModel

createModel(ctx.request().getResource(), CountryListImpl.class);

Reference: https://medium.com/@veena.vikraman19/aem-junit-for-simple-aem-component-with-multifield-2326f61c8982 

Mahedi Sabuj