Expand my Community achievements bar.

Radically easy to access on brand approved content for distribution and omnichannel performant delivery. AEM Assets Content Hub and Dynamic Media with OpenAPI capabilities is now GA.
SOLVED

Junit Coverage for Core Teaser Component

Avatar

Level 2

Hi Team,

 

 I have written jUnit test cases for custom teaser component which extends the core Teaser component using the Delegation Pattern for Sling Models using "@Self @Via(type=ResourceSuperType.class)  as specified here: https://github.com/adobe/aem-core-wcm-components/wiki/Delegation-Pattern-for-Sling-Models

 

Junit coverage is less on environment, in my local it is 100 % I have covered junits for custom methods which written custom teaser model, There are methods in parent class ( below in screenshot ) which does not cover in my custom test class, How to overcome this issue?

 

gskittu_0-1677844904812.png

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

@gskittu Have a getter method which returns Teaser teaser which you have injected @Self and @Via
Just showing an example below you can follow the same pattern while dealing with any delegate slingmodels

Example.class

krishna_sai_0-1677846599780.png

ExampleTest.java

krishna_sai_1-1677846631886.png

 



Hope this helps,
Krishna

View solution in original post

4 Replies

Avatar

Correct answer by
Community Advisor

@gskittu Have a getter method which returns Teaser teaser which you have injected @Self and @Via
Just showing an example below you can follow the same pattern while dealing with any delegate slingmodels

Example.class

krishna_sai_0-1677846599780.png

ExampleTest.java

krishna_sai_1-1677846631886.png

 



Hope this helps,
Krishna

Avatar

Level 2

Thanks you Krishna, There are some more methods which we don't require, With those fields coverage is less, how can we fix this issue

Avatar

Community Advisor

@gskittu you can do check for asserNull for methods which you are not using

Avatar

Level 7

I have below extended from Teaser. I have written JUnit class for this But I see teaser object as null. How did you inject teaser in your JUnit Test class.

 

Thanks for any help.

custom model class implements Teaser.

 

@Model(
		adaptables = {SlingHttpServletRequest.class},
		adapters = {Teaser.class, TargetDateFund.class, ComponentExporter.class},
		resourceType = {TargetDateFundImpl.RESOURCE_TYPE},
		defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL
)
@Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME , extensions = ExporterConstants.SLING_MODEL_EXTENSION)
public class TargetDateFundImpl implements TargetDateFund
{
	protected static final String RESOURCE_TYPE = "pi-web/components/content/targetdatefund";

	@SlingObject
	private ResourceResolver resourceResolver;

	@Self
	@Required
	private SlingHttpServletRequest request;

	@Self
	@Via(type = ResourceSuperType.class)
	private com.adobe.cq.wcm.core.components.models.Teaser teaser;

	@ScriptVariable
	private ValueMap properties;

	@Inject
	private ModelFactory modelFactory;

	@Inject
	private SlingModelFilter slingModelFilter;

	private String fragmentPath;

	private String hedgeText;

	private Map<String, ComponentExporter> childModels = null;

	@PostConstruct
	protected void initModel() {
		fragmentPath = properties.get("fragmentPath", String.class);
		if (StringUtils.isNotEmpty(fragmentPath)) {
			Resource fragmentResource = resourceResolver.getResource(fragmentPath);
			if (fragmentResource != null) {
				Optional<ContentFragment> contentFragment = Optional.ofNullable(fragmentResource.adaptTo(ContentFragment.class));
				hedgeText = contentFragment.map(cf -> cf.getElement("main")).map(ContentElement::getContent)
						.orElse(org.apache.commons.lang.StringUtils.EMPTY);
			}
		}
	}

	@Override
	public String getFragmentPath() {
		return fragmentPath;
	}

	@Override
	public String getHedgeText() { return hedgeText; }

	/** properties extended from teaser**/
	@Override
	public boolean isActionsEnabled() {
		return teaser.isActionsEnabled();
	}

	@Override
	public List<ListItem> getActions() {
		return teaser.getActions();
	}

	@Override
	public  Link getLink() {
		return teaser.getLink();
	}

	@Override
	public String getLinkURL() {
		return teaser.getLinkURL();
	}

	@Override
	public Resource getImageResource() {
		return teaser.getImageResource();
	}

	@Override
	public boolean isImageLinkHidden() {
		return teaser.isImageLinkHidden();
	}

	@Override
	public String getPretitle() {
		return teaser.getPretitle();
	}

	@Override
	public String getTitle() {
		return teaser.getTitle();
	}

	@Override
	public boolean isTitleLinkHidden() {
		return teaser.isTitleLinkHidden();
	}

	@Override
	public String getDescription() {
		return teaser.getDescription();
	}

	@Override
	public String getTitleType() {
		return teaser.getTitleType();
	}

	@Override
	public  String getId() {
		return teaser.getId();
	}

	@Override
	public  ComponentData getData() {
		return teaser.getData();
	}

	@Override
	public  String getAppliedCssClasses() {
		return teaser.getAppliedCssClasses();
	}

	@Override
	public  String getExportedType() {
		return TargetDateFundImpl.RESOURCE_TYPE;
	}

	@NotNull
	@Override
	public Map<String, ? extends ComponentExporter> getExportedItems() {
		if (childModels == null) {
			childModels = getChildModels(request, ComponentExporter.class);
		}

		return childModels;
	}

	@NotNull
	@Override
	public String[] getExportedItemsOrder() {
		Map<String, ? extends ComponentExporter> models = getExportedItems();

		if (models.isEmpty()) {
			return ArrayUtils.EMPTY_STRING_ARRAY;
		}

		return models.keySet().toArray(ArrayUtils.EMPTY_STRING_ARRAY);

	}

	/**
	 * Returns a map (resource name => Sling Model class) of the given resource
	 * children's Sling Models that can be adapted to {@link T}.
	 *
	 *  slingRequest the current request
	 *  modelClass   the Sling Model class to be adapted to
	 *  a map (resource name => Sling Model class) of the given resource
	 *         children's Sling Models that can be adapted to {@link T}
	 */
	@NotNull
	private <T> Map<String, T> getChildModels(@NotNull SlingHttpServletRequest slingRequest,
											   Class<T> modelClass) {
		Map<String, T> itemWrappers = new LinkedHashMap<>();

		for (final Resource child : slingModelFilter.filterChildResources(request.getResource().getChildren())) {
			itemWrappers.put(child.getName(), modelFactory.getModelFromWrappedRequest(slingRequest, child, modelClass));
		}

		return itemWrappers;
	}
	/** END exptended proeprties **/
}

 

JUnit

import com.adobe.cq.dam.cfm.ContentElement;
import com.adobe.cq.dam.cfm.ContentFragment;
import com.adobe.cq.wcm.core.components.models.Teaser;
import io.wcm.testing.mock.aem.junit5.AemContext;
import io.wcm.testing.mock.aem.junit5.AemContextExtension;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.models.factory.ModelFactory;
import org.apache.sling.testing.mock.sling.ResourceResolverType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.logging.Logger;

import static org.junit.jupiter.api.Assertions.*;

@ExtendWith({ AemContextExtension.class, MockitoExtension.class })
class TargetDateFundImplTest {

    private final AemContext context = new AemContext(ResourceResolverType.JCR_MOCK);

    @InjectMocks
    private TargetDateFundImpl targetDateFund;

    @Mock
    Teaser teaser;

    @Mock
    private ModelFactory modelFactory;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.initMocks(this);

        context.load().json("/components/teaser/test-content.json", "/content");
        context.load().json("/dam/content-fragments/simplecf.json", "/content/dam/cfs");

        context.currentPage("/content/teasers");
        context.currentResource("/content/teasers/jcr:content/root/responsivegrid/teaser-2");

        context.registerService(ModelFactory.class, modelFactory);
        targetDateFund = context.request().adaptTo(TargetDateFundImpl.class);
    }

    @test
    void getFragmentPath() {
        assertNotNull(targetDateFund.getFragmentPath());
    }

    @test
    void getHedgeText() {
        assertNotNull(targetDateFund.getHedgeText());
    }

}