All AEM as a Cloud Service skills: component development, Workflow model design, development, triggering, launchers, debugging, and triaging, Dispatcher config authoring, advisory, incident response, performance tuning, and security hardening, Rapid Development Environment (RDE) deployment, log inspection, snapshots, and troubleshooting via `aio aem rde`, Jackrabbit Oak query/index tuning (property, Lucene index definitions), and extracting/inventorying JCR queries (XPath, SQL2, QueryBuilder) across a codebase.
85%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
Patterns for creating unit tests using wcm.io AEM Mocks with JUnit 5.
Resource.adaptTo() is a final method and cannot be mocked.
// WRONG - Will fail
Resource resource = mock(Resource.class);
when(resource.adaptTo(MyModel.class)).thenReturn(mockModel); // FAILS!
// CORRECT - Use AemContext
Resource resource = context.create().resource("/content/test", "title", "Test");
MyModel model = resource.adaptTo(MyModel.class);@BeforeEach
void setUp() {
context.addModelsForClasses(ParentModel.class, ChildItemModel.class);
}// CORRECT
Resource parent = context.create().resource("/content/test", "title", "My Title");
context.create().resource("/content/test/items/item0", "itemTitle", "Item 1");
ParentModel model = parent.adaptTo(ParentModel.class);
// WRONG - Too complex, error-prone
Resource parent = mock(Resource.class);
when(parent.getValueMap()).thenReturn(...);package [package].models;
import static org.junit.jupiter.api.Assertions.*;
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;
// NOTE: Projects MAY have a custom `AppAemContext` helper class that pre-registers
// common services or content. Using `new AemContext()` directly works universally
// with just the wcm.io AEM Mocks dependency.
@ExtendWith(AemContextExtension.class)
class ComponentNameModelTest {
private final AemContext context = new AemContext();
private Page page;
private Resource componentResource;
@BeforeEach
void setUp() {
context.addModelsForClasses(ComponentNameModel.class);
page = context.create().page("/content/[project]/test-page");
}
@Test
void testWithCompleteData() {
// Arrange
componentResource = context.create().resource(page, "component",
"sling:resourceType", "[project]/components/component-name",
"title", "Test Title",
"description", "Test Description");
// Act
ComponentNameModel model = componentResource.adaptTo(ComponentNameModel.class);
// Assert
assertNotNull(model);
assertEquals("Test Title", model.getTitle());
assertEquals("Test Description", model.getDescription());
assertTrue(model.hasContent());
}
@Test
void testWhenEmpty() {
componentResource = context.create().resource(page, "component",
"sling:resourceType", "[project]/components/component-name");
ComponentNameModel model = componentResource.adaptTo(ComponentNameModel.class);
assertNotNull(model);
assertNull(model.getTitle());
assertFalse(model.hasContent());
}
}void testMethodName_Scenario() { }
// Examples:
void testGetTitle_WithValidTitle() { }
void testGetTitle_WhenTitleIsNull() { }
void testHasContent_WithCompleteData() { }
void testHasContent_WhenEmpty() { }
void testGetItems_WithMultipleItems() { }
void testGetItems_WhenNoItems() { }@Test
void testWithCompleteData() {
// All properties populated
// Assert all getters return expected values
// Assert hasContent() returns true
}
@Test
void testWhenEmpty() {
// No properties
// Assert getters return null/empty
// Assert hasContent() returns false
}
@Test
void testWithPartialData() {
// Some properties
// Assert populated properties return values
// Assert unpopulated return null
}@Test
void testWithMultipleItems() {
Resource parent = context.create().resource("/content/test", "listTitle", "List");
context.create().resource("/content/test/items/item0", "itemTitle", "Item 1");
context.create().resource("/content/test/items/item1", "itemTitle", "Item 2");
ParentModel model = parent.adaptTo(ParentModel.class);
assertNotNull(model);
assertEquals(2, model.getItems().size());
assertEquals("Item 1", model.getItems().get(0).getItemTitle());
}
@Test
void testWithSingleItem() {
Resource parent = context.create().resource("/content/test");
context.create().resource("/content/test/items/item0", "itemTitle", "Only Item");
ParentModel model = parent.adaptTo(ParentModel.class);
assertEquals(1, model.getItems().size());
}
@Test
void testWithNoItems() {
Resource parent = context.create().resource("/content/test");
ParentModel model = parent.adaptTo(ParentModel.class);
assertNotNull(model.getItems());
assertTrue(model.getItems().isEmpty());
}@Test
void testImageWithReference() {
componentResource = context.create().resource(page, "component");
context.create().resource(componentResource, "image",
"fileReference", "/content/dam/[project]/image.jpg");
ComponentModel model = componentResource.adaptTo(ComponentModel.class);
assertEquals("/content/dam/[project]/image.jpg", model.getImageReference());
}
@Test
void testImageWithoutReference() {
componentResource = context.create().resource(page, "component");
ComponentModel model = componentResource.adaptTo(ComponentModel.class);
assertNull(model.getImageReference());
}Resource resource = context.create().resource(page, "component",
"sling:resourceType", "[project]/components/example",
"title", "Test Title",
"description", "Test Description");Resource component = context.create().resource(page, "component",
"sling:resourceType", "[project]/components/example",
"listTitle", "My List");
context.create().resource(component, "items/item0",
"title", "Item 1 Title",
"description", "Item 1 Description");
context.create().resource(component, "items/item1",
"title", "Item 2 Title");context.create().resource(itemResource, "tileImage",
"fileReference", "/content/dam/[project]/image.jpg",
"fileName", "image.jpg");// Null checks
assertNotNull(model);
assertNull(model.getOptionalField());
// Equality
assertEquals("expected", model.getActualValue());
assertEquals(3, model.getItems().size());
// Boolean
assertTrue(model.hasContent());
assertFalse(model.isEmpty());
// Collections
assertNotNull(model.getItems());
assertTrue(model.getItems().isEmpty());| Code Pattern | Tests Needed |
|---|---|
| Simple getter | 2 (with value, null) |
| Conditional (if/else) | 2+ (each branch) |
| Multifield init | 4 (null, empty, single, multiple) |
| Ternary operator | 2 (true, false) |
when(resource.adaptTo(MyModel.class)).thenReturn(mockModel); // FAILS!// Returns null without registration
MyModel model = resource.adaptTo(MyModel.class);Fix: context.addModelsForClasses(MyModel.class)
context.create().resource("/content/test/item0"); // Won't be foundFix: Match dialog structure:
context.create().resource("/content/test/items/item0");Before submitting tests:
@BeforeEachcontext.create().resource() (not mocks)hasContent() tested for true and false.tessl-plugin
skills
aem-rde
aem-workflow
code-assessment
content-distribution
create-component
assets
references
dispatcher
incident-response
references
dispatcher-foundation
performance-tuning
references
dispatcher-foundation
security-hardening
references
dispatcher-foundation
technical-advisory
references
dispatcher-foundation
workflow-orchestrator
references
dispatcher-foundation
ensure-agents-md
references
migration
references
dispatcher
legacy-ui
template-modernization
validation
scripts
dispatcher-tool
validate-migration