HomeBackend Development › Unit & integration testing

Unit & integration testing

Purpose: Test AEM backend code without a running instance using wcm.io AEM Mocks, plus when to write integration tests.

Who this page is for

AudienceWhy it matters to you
Backend engineersNon-negotiable for every model/service

The stack

LayerTool
Unit (models, services, servlets)JUnit 5 + wcm.io AEM Mocks (io.wcm.testing.mock.aem.junit5)
Repository fixturesJSON files loaded into the mock context
Integration (against real AEM)it.tests module, HTTP-level — reserve for critical flows

Model test example

@ExtendWith(AemContextExtension.class)
class PlanCardModelTest {
    private final AemContext ctx = new AemContext();

    @BeforeEach void setUp() {
        ctx.addModelsForClasses(PlanCardModel.class);
        ctx.load().json("/fixtures/plan-card.json", "/content/plan");
    }

    @Test void derivesCoveredCount() {
        ctx.currentResource("/content/plan/goldcard");
        PlanCardModel model = ctx.request().adaptTo(PlanCardModel.class);
        assertEquals(2, model.getCoveredCount());
    }

    @Test void survivesEmptyContent() {
        ctx.create().resource("/content/plan/empty",
            "sling:resourceType", "phi-academy/components/plancard");
        ctx.currentResource("/content/plan/empty");
        assertNotNull(ctx.request().adaptTo(PlanCardModel.class));
    }
}

The fixture JSON mirrors real content (copy from .infinity.json on your local instance, then trim).

What to test

AlwaysRarely
Derived getters / business logicHTL rendering (integration concern)
Empty/missing content behaviourAdobe product code
Servlet status codes & JSON shapeGetters that only return injected values
Service config permutations

React translation

Same philosophy as testing hooks with a mock store: fixture state in, assertions on the adapted output, no real backend needed. If a model is hard to test, it is doing too much — split it.

Quick navigation