Expand my Community achievements bar.

Learn about Edge Delivery Services in upcoming GEM session
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());
    }

}