Skip to main content

Testing

Testing in AEM usually combines unit tests for backend logic, integration tests for content and services, and UI tests for authoring behavior.

Test pyramid (AEM)

  1. Unit tests: Fast, isolated tests (models, services, utilities).
  2. Integration tests: Repository + OSGi wiring in a test context.
  3. UI tests: Authoring and end-to-end flows in a browser.

What to cover

  • Unit tests: Sling Models, services, and utilities.
  • Integration tests: Repository interactions and OSGi configs.
  • UI tests: Authoring flows and component dialogs.

Tools and frameworks

  • JUnit 5 for Java tests.
  • AEM Mocks for unit and integration-style tests.
  • Sling Testing utilities for request/response helpers.
  • Playwright/Cypress for authoring and UI flows.

Example: Sling Model unit test

@ExtendWith(AemContextExtension.class)
class TitleModelTest {

private final AemContext ctx = new AemContext();

@BeforeEach
void setUp() {
ctx.addModelsForClasses(TitleModel.class);
ctx.create().resource("/content/page/jcr:content",
"jcr:title", "Hello",
"sling:resourceType", "myproject/components/title");
}

@Test
void readsTitle() {
Resource resource = ctx.resourceResolver().getResource("/content/page/jcr:content");
TitleModel model = resource.adaptTo(TitleModel.class);
assertEquals("Hello", model.getTitle());
}
}

Example: Service test with OSGi config

@ExtendWith(AemContextExtension.class)
class FeatureServiceTest {

private final AemContext ctx = new AemContext();

@BeforeEach
void setUp() {
ctx.registerInjectActivateService(new FeatureServiceImpl(),
"enabled", true,
"threshold", 10);
}

@Test
void featureIsEnabled() {
FeatureService service = ctx.getService(FeatureService.class);
assertTrue(service.isEnabled());
}
}

Example: Integration-style repository test

@ExtendWith(AemContextExtension.class)
class ContentQueryTest {

private final AemContext ctx = new AemContext();

@BeforeEach
void setUp() {
ctx.create().resource("/content/site/en",
"jcr:title", "Home",
"sling:resourceType", "myproject/components/page");
}

@Test
void findByPath() {
ResourceResolver resolver = ctx.resourceResolver();
Resource resource = resolver.resolve("/content/site/en");
assertFalse(ResourceUtil.isNonExistingResource(resource));
}
}

Example: Load JSON content for Sling Models

You can load JSON content into the AemContext from your test resources folder and adapt the resource to a model.

@ExtendWith(AemContextExtension.class)
class TeaserModelTest {

private final AemContext ctx = new AemContext();

@BeforeEach
void setUp() {
ctx.addModelsForClasses(TeaserModel.class);
ctx.load().json("/content/teaser.json", "/content/site/en");
}

@Test
void readsTeaserProperties() {
Resource resource = ctx.resourceResolver().getResource("/content/site/en/jcr:content/root/teaser");
TeaserModel model = resource.adaptTo(TeaserModel.class);

assertEquals("My Teaser", model.getTitle());
assertEquals("/content/site/en/page", model.getLink());
}
}

Example JSON file in test resources:

src/test/resources/content/teaser.json
{
"jcr:primaryType": "cq:Page",
"jcr:content": {
"jcr:primaryType": "cq:PageContent",
"root": {
"jcr:primaryType": "nt:unstructured",
"teaser": {
"jcr:primaryType": "nt:unstructured",
"sling:resourceType": "myproject/components/teaser",
"title": "My Teaser",
"link": "/content/site/en/page"
}
}
}
}

UI testing guidance

  • Keep UI tests minimal and focused on critical authoring flows.
  • Prefer stable selectors (data attributes) over text-based selectors.
  • Run UI tests against a predictable environment (local SDK or dedicated test env).

Smoke test checklist

  • Create a page with core components and custom components.
  • Open each dialog and verify defaults and validations.
  • Publish and verify rendering on publish.
  • Check 404s and clientlib loading.

CI tips

  • Run unit tests on every commit.
  • Run integration tests nightly or on main merges.
  • Keep UI tests in a separate stage to avoid slowing down PR checks.

Practical tips

  • Prefer fast unit tests for business logic.
  • Keep integration tests focused on content structure and permissions.
  • Smoke-test authoring scenarios before releases.

See also