Home > Software design >  Unit testing extended AEM core component - delegate pattern null reference exception
Unit testing extended AEM core component - delegate pattern null reference exception

Time:08-28

I am trying to write a unit test for an extended AEM core component - a 'button' with an extra field. I use the delegation pattern, and Lombok to reduce implementation code.

My unit test is failing when attempting to get the button ID (inherited from the button super-type) - with a null reference exception - because 'button' is null.

Why would that be? Have I set up my unit test incorrectly? Or could it be that I have used the delegation pattern for the core component incorrectly?

It is driving me crazy!

INTERFACE:

@ProviderType
public interface ExtendedButton extends Button {
    String RESOURCE_TYPE = "myproject/components/extendedbutton";

    String getVariant();
}

IMPL:

@Model(
    adaptables = { Resource.class, SlingHttpServletRequest.class },
    adapters = { ExtendedButton.class, Button.class, ComponentExporter.class },
    resourceType = ExtendedButton.RESOURCE_TYPE,
    defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL
)
@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION)
public class ExtendedButtonImpl implements ExtendedButton {
    @Delegate
    @Self
    @Via(type = ResourceSuperType.class)
    private Button button;

    @ValueMapValue
    @Getter
    private String variant;

    // EXAMPLE
    // without lombok, the getter for button ID would be;
    public String getId() {
        return (null != button) ? button.getId() : null;
    }
}

UNIT TEST CODE:

@ExtendWith(AemContextExtension.class)
class ExtendedButtonModelTest {
    private final AemContext context = new AemContextBuilder()
            .plugin(CORE_COMPONENTS)
            .build();

    private ExtendedButton model;

    @BeforeEach
    public void setup() {
        context.create().resource("/apps/myproject/components/extendedbutton",
                PROPERTY_RESOURCE_SUPER_TYPE, "core/wcm/components/button/v2/button");

        Page page = context.create().page("/content/test-page");

        context.currentResource(context.create().resource(page, "extendedbutton",
                PROPERTY_RESOURCE_TYPE, ExtendedButton.RESOURCE_TYPE,
                JCR_TITLE, "button text",

                "variant", "light",

                "id", "button id",
                "linkURL", "https://google.com",
                "linkTarget", "_blank",
                "accessibilityLabel", "button label"
        ));

        model = context.request().adaptTo(ExtendedButton.class);
    }

    // UNIT TEST SUCCEEDS
    @Test
    void testGetVariant() {
        String val = model.getVariant();
        assertNotNull(val);
        assertEquals("light", val);
    }

    // UNIT TEST THROWS NULL POINTER EXCEPTION ON MODEL
    @Test
    void testGetButtonId() {
        String val = model.getId();
        assertNotNull(val);
        assertEquals("button-id", val);
    }
}

CodePudding user response:

Oh my! This turned out to be a very, very simple issue. In the above unit test code, I used two constants;

PROPERTY_RESOURCE_SUPER_TYPE
PROPERTY_RESOURCE_TYPE

These were incorrect - and from the wrong import library, since they were "resourceSuperType" and "resourceType" respectively - missing the "sling:" prefix!!!!!!

The correct constants, are;

import static org.apache.sling.jcr.resource.api.JcrResourceConstants.SLING_RESOURCE_SUPER_TYPE_PROPERTY;
import static org.apache.sling.jcr.resource.api.JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY;

The fundamental line to the unit test, being;

context.create().resource("/apps/myproject/components/extendedbutton",
                SLING_RESOURCE_SUPER_TYPE_PROPERTY, "core/wcm/components/button/v2/button");

which instructs the unit test which core component to extend from.

  • Related