Expand my Community achievements bar.

Enhance your AEM Assets & Boost Your Development: [AEM Gems | June 19, 2024] Improving the Developer Experience with New APIs and Events

How to write Junit for workflow

Avatar

Level 2

Please find the below sample code .How to write Junit for workflow

 

public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap metaDataMap) {
            ResourceResolver resourceResolver = null;
        try {
Session session = workflowSession.adaptTo(Session.class);
Map<String, Object> map = new HashMap<>();
map.put(mysession, session); 
resourceResolver=resourceResolver.getResourceResolver(resourceResolverFactory, map);
WorkflowData workflowData = workItem.getWorkflowData();
String path = workflowData.getPayload().toString();  
  Resource resource = resourceResolver.getResource(path);
ValueMap valuemap = resource.getValueMap();
String prop = valueMap.get("dc:title", String.class);
Resource metadataresource = resourceResolver.getResource(resource.getPath() + "/metadata");
ModifiableValueMap mvaluemap = metadataresource.adaptTo(ModifiableValueMap.class);
mvaluemap.put(mymetadata:title, prop);
 
 
    } catch (Exception e) {
logger.info("my exception", e.getMessage());
    }
     } 
Any suggestion will really help. Thanks
14 Replies

Avatar

Community Advisor

Hi @DillipDi 

1.Create a mock WorkItem, WorkflowSession, and MetaDataMap objects.

2.Create a mock ResourceResolver object using a mocking framework like Mockito.

3.Mock the required methods of the ResourceResolver object to return the expected values.

4.Create an instance of the class containing the execute method.Call the execute method with the mock objects.

5.Verify that the expected methods of the mock objects were called with the expected parameters.

import static org.mockito.Mockito.*;

import java.util.HashMap;
import java.util.Map;

import javax.jcr.Session;

import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.ValueMapDecorator;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class WorkflowTest {

    @Mock
    private WorkItem workItem;

    @Mock
    private WorkflowSession workflowSession;

    @Mock
    private MetaDataMap metaDataMap;

    @Mock
    private ResourceResolverFactory resourceResolverFactory;

    @Mock
    private ResourceResolver resourceResolver;

    @Mock
    private Session session;

    @Mock
    private Resource resource;

    @Mock
    private Resource metadataResource;

    private Workflow workflow;

    @Before
    public void setUp() throws Exception {
        Map<String, Object> map = new HashMap<>();
        map.put("mysession", session);
        when(resourceResolverFactory.getResourceResolver(map)).thenReturn(resourceResolver);

        when(workItem.getWorkflowData()).thenReturn(new WorkflowData(new ValueMapDecorator(new HashMap<>())));
        when(workItem.getWorkflowData().getPayload()).thenReturn("/content/sample");

        when(resourceResolver.getResource("/content/sample")).thenReturn(resource);
        ValueMap valueMap = new ValueMapDecorator(new HashMap<>());
        valueMap.put("dc:title", "Sample Title");
        when(resource.getValueMap()).thenReturn(valueMap);

        when(resourceResolver.getResource("/content/sample/metadata")).thenReturn(metadataResource);
        ModifiableValueMap mValueMap = new ValueMapDecorator(new HashMap<>());
        when(metadataResource.adaptTo(ModifiableValueMap.class)).thenReturn(mValueMap);

        workflow = new Workflow();
    }

    @Test
    public void testExecute() throws Exception {
        workflow.execute(workItem, workflowSession, metaDataMap);

        verify(resourceResolverFactory).getResourceResolver(anyMap());
        verify(workItem).getWorkflowData();
        verify(workItem.getWorkflowData()).getPayload();
        verify(resourceResolver).getResource("/content/sample");
        verify(resource).getValueMap();
        verify(resourceResolver).getResource("/content/sample/metadata");
        verify(metadataResource).adaptTo(ModifiableValueMap.class);
        verify(metadataResource.adaptTo(ModifiableValueMap.class)).put("mymetadata:title", "Sample Title");
    }
}


Avatar

Level 2

Hi @Raja_Reddy Thanks for ur quick reply . I tried the above code getting error like 

Cannot instantiate the type WorkflowData
Type mismatch: cannot convert from ValueMapDecorator to ModifiableValueMap

 

 

Avatar

Community Advisor

Try this

 

Replace WorkflowData with WorkflowDataImpl in the setUp() method. ValueMapDecorator with ModifiableValueMapDecorator in the setUp() method.

 

when(workItem.getWorkflowData()).thenReturn(new WorkflowDataImpl(new ValueMapDecorator(new HashMap<>()))); 

 

 



Avatar

Level 2

Hi @Raja_Reddy thanks for ur reply getting same error .

 

Cannot instantiate the type WorkflowDataImpl

Avatar

Level 5

HI @DillipDi 

The type mismatch is due to the ValueMapDecorator class that does not directly implement the ModifiableValueMap interface

You can try using ModifiableValueMapDecorator which directly implements 

ModifiableValueMap interface
 
Reference: 

 https://sling.apache.org/apidocs/sling7/org/apache/sling/api/wrappers/ValueMapDecorator.html

Avatar

Level 8

Hi @DillipDi ,

To write JUnit tests for workflows, you need to simulate the workflow execution and then verify that the expected actions are performed. In your case, you want to test the execute method of your workflow process step. Here's how you can write JUnit tests for it:

 

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.api.wrappers.ValueMapDecorator;
import org.apache.sling.commons.testing.sling.MockResourceResolver;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;

import javax.jcr.Node;
import javax.jcr.Session;
import java.util.HashMap;
import java.util.Map;

@RunWith(MockitoJUnitRunner.class)
public class YourWorkflowProcessTest {

    @Mock
    private WorkItem workItem;

    @Mock
    private WorkflowSession workflowSession;

    @Mock
    private Session session;

    private YourWorkflowProcess workflowProcess;

    @Before
    public void setUp() throws Exception {
        workflowProcess = new YourWorkflowProcess();
    }

    @Test
    public void testExecute() throws Exception {
        // Mocking payload path and title
        String payloadPath = "/content/sample";
        String title = "Sample Title";

        // Mocking resource resolver
        MockResourceResolver resourceResolver = new MockResourceResolver();

        // Mocking resource and metadata resource
        Resource payloadResource = Mockito.mock(Resource.class);
        Mockito.when(payloadResource.getPath()).thenReturn(payloadPath);

        Resource metadataResource = Mockito.mock(Resource.class);
        Mockito.when(resourceResolver.getResource(payloadPath + "/metadata")).thenReturn(metadataResource);

        // Mocking value map for payload resource
        Map<String, Object> payloadProperties = new HashMap<>();
        payloadProperties.put("dc:title", title);
        ValueMap payloadValueMap = new ValueMapDecorator(payloadProperties);
        Mockito.when(payloadResource.getValueMap()).thenReturn(payloadValueMap);

        // Mocking modifiable value map for metadata resource
        Map<String, Object> metadataProperties = new HashMap<>();
        Mockito.when(metadataResource.adaptTo(ModifiableValueMap.class)).thenReturn(new ValueMapDecorator(metadataProperties));

        // Mocking workflow data
        WorkflowData workflowData = Mockito.mock(WorkflowData.class);
        Mockito.when(workItem.getWorkflowData()).thenReturn(workflowData);
        Mockito.when(workflowData.getPayload()).thenReturn(payloadResource);

        // Mocking session
        Mockito.when(workflowSession.adaptTo(Session.class)).thenReturn(session);

        // Executing the workflow process
        workflowProcess.execute(workItem, workflowSession, new MetaDataMap());

        // Verifying if the title property is set in metadata
        Mockito.verify(metadataResource, Mockito.times(1)).adaptTo(ModifiableValueMap.class);
        Mockito.verify(metadataResource.adaptTo(ModifiableValueMap.class), Mockito.times(1)).put("mymetadata:title", title);
    }
}

 

In this test:

  • We mock the necessary objects such as WorkItem, WorkflowSession, ResourceResolver, etc.
  • We set up mock behavior for methods used within the execute method.
  • We execute the execute method of the workflow process.
  • We verify that the expected actions, such as setting the title property in metadata, are performed.

Make sure to replace YourWorkflowProcess with the actual name of your workflow process class. This test verifies that the workflow process performs the expected actions when executed.

Avatar

Level 2

Hi @HrishikeshKa thanks for ur time to reply .i tried ur above code but getting the below error

 

java.lang.ClassCastException: class org.apache.sling.api.wrappers.ValueMapDecorator cannot be cast to class org.apache.sling.api.resource.ModifiableValueMap

Avatar

Level 8

Hi @DillipDi ,

It seems like you're trying to mock the adaptation of a resource to a ModifiableValueMap using ValueMapDecorator, which is causing the ClassCastException. The issue lies in this line:

 

Mockito.when(metadataResource.adaptTo(ModifiableValueMap.class)).thenReturn(new ValueMapDecorator(metadataProperties));

 

ValueMapDecorator does not implement ModifiableValueMap, so you cannot cast it directly. Instead, you should mock the ModifiableValueMap interface directly.

Here's how you can fix it:

 

// Mocking modifiable value map for metadata resource
ModifiableValueMap metadataValueMap = Mockito.mock(ModifiableValueMap.class);
Mockito.when(metadataResource.adaptTo(ModifiableValueMap.class)).thenReturn(metadataValueMap);

 

 Then, you can use metadataValueMap to manipulate properties:
// Setting properties on the mock ModifiableValueMap
metadataValueMap.put("mymetadata:title", title);
By doing this, you are properly mocking the ModifiableValueMap interface, avoiding the ClassCastException.

Avatar

Level 8

Hi @DillipDi ,

 

I can see some issue with the code which you have shared.

resourceResolver=resourceResolver.getResourceResolver(resourceResolverFactory, map);

There is no such method in resourceResolver object and that to you are trying to call that method on a null object which you have defined at starting of the method.

 

Please check whether the snippet you have shared is correct or not, if possible try to share complete class.

 

 

 

Avatar

Level 2

Hi @sravs plz find the working code. while pasting the code here that line got changed.

 

public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap metaDataMap) {
            ResourceResolver resourceResolver = null;
        try {
Session session = workflowSession.adaptTo(Session.class);
Map<String, Object> map = new HashMap<>();
map.put(mysession, session); 
resourceResolver = resourceResolverFactory.getResourceResolver(map);
WorkflowData workflowData = workItem.getWorkflowData();
String path = workflowData.getPayload().toString();  
  Resource resource = resourceResolver.getResource(path);
ValueMap valuemap = resource.getValueMap();
String prop = valueMap.get("dc:title", String.class);
Resource metadataresource = resourceResolver.getResource(resource.getPath() + "/metadata");
ModifiableValueMap mvaluemap = metadataresource.adaptTo(ModifiableValueMap.class);
mvaluemap.put(mymetadata:title, prop);
 
 
    } catch (Exception e) {
logger.info("my exception", e.getMessage());
    }
     } 

Avatar

Level 8

Hi @DillipDi ,

 

Can you please try with below snippet

import com.adobe.granite.workflow.WorkflowSession;
import com.adobe.granite.workflow.exec.WorkItem;
import com.adobe.granite.workflow.exec.WorkflowData;
import com.adobe.granite.workflow.metadata.MetaDataMap;
import com.adobe.granite.workflow.metadata.SimpleMetaDataMap;
import io.wcm.testing.mock.aem.junit5.AemContext;
import io.wcm.testing.mock.aem.junit5.AemContextExtension;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import javax.jcr.Session;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.Mockito.when;

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

    private AemContext context = new AemContext();

    @InjectMocks
    private YourWorkflowProcess workflowProcess;

    @Mock
    WorkflowData payload;

    @Mock
    WorkItem workItem;

    @Mock
    WorkflowSession workflowSession;
    @Mock
    Session session;

    @Mock
    ResourceResolverFactory resourceResolverFactory;

    @Test
    void execute() throws LoginException {
        String path = "/content/dam/sample/resource";
        String metaPath = "/content/dam/sample/resource/metadata";
        context.create().resource(path,"dc:title","Sample");
        context.create().resource(metaPath, "jcr:primaryType","nt:unstructured");
        when(workflowSession.adaptTo(Session.class)).thenReturn(session);
        when(resourceResolverFactory.getResourceResolver(anyMap())).thenReturn(context.resourceResolver());
        when(workItem.getWorkflowData()).thenReturn(payload);
        when(payload.getPayload()).thenReturn(path);
        MetaDataMap map = new SimpleMetaDataMap();
        workflowProcess.execute(workItem, workflowSession, map);
        String metaProp = context.resourceResolver().getResource(metaPath).getValueMap().get("mymetadata:title",
                String.class);
        assertEquals(metaProp, "Sample");
    }
}

Avatar

Level 2

Hi @sravs  Thanks for ur time to reply .Let me check this and let u know .

Avatar

Administrator

@DillipDi Did you find the suggestions from users helpful? Please let us know if more information is required. Otherwise, please mark the answer as correct for posterity. If you have found out solution yourself, please share it with the community.



Kautuk Sahni

Avatar

Administrator

@DillipDi If you have found out solution yourself, please share it with the community.



Kautuk Sahni