Expand my Community achievements bar.

SOLVED

AEM Assets Workflow Junits

Avatar

Level 2

Hello,
I have a test workflow written in aem where i need to get the Asset

where the java test case is written as:

 

 
import javax.jcr.RepositoryException;
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 org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

 
//import com.day.cq.dam.api.Asset;  //if i am using this import then its working fine
import com.adobe.granite.asset.api.Asset;  //but i want for this import
import com.adobe.granite.workflow.WorkflowException;

import io.wcm.testing.mock.aem.junit5.*;

@ExtendWith({ AemContextExtension.class, MockitoExtension.class })
class ExampleTest
{
    AemContext aemContext = new AemContext();

    @Mock
    Resource resource;

    @BeforeEach
    void setup() throws Exception
    {
        aemContext.load().json("com/example/test.json", "/content/dam");
    }

    @Test
    void testExecute() throws WorkflowException, RepositoryException {
        String resourcePath = "/content/dam/test";
        resource = aemContext.resourceResolver().getResource(resourcePath);
        System.out.println(resource.getPath()); // Output: resource path: /content/dam/test
        Asset asset = resource.adaptTo(Asset.class);
        System.out.println(asset.getPath()); // Output: asset path: null 
    }

}

JsonFile

{

"test":

{

"jcr:primaryType":"dam:Asset",

"jcr:createdBy":"admin"

}

}

 

please help me solve from above code on how to get the asset path/object so that i can retrive asset.getPath(), asset.getName() asset.getAssetMetadata()  if required 

for now its giving the value as null
request to share the sample code


Thanks & Regards.

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

Correct. It will return null if you use the com.adobe.granite.asset.api.Asset because it is not adaptable. Why are you using that? You should use the Asset implementation from com.day.cq.dam.api.Asset.

If you really want to stick with the other Asset implementation, you need to mock that class and not rely on the aemContext object. That's what I suggested as option #1 in my previous response. You should mock all of the following objects: ResourceResolver, the AdaptTo method, the AssetManager, and the Asset. The drawback with this approach is that you are not testing anything because you are setting the expected value at each step. So the best solution is to use the correct Asset implementation.

 

Hope this helps

 

 



Esteban Bustamante

View solution in original post

11 Replies

Avatar

Level 9

Hi @VJain03 ,

 

Create an asset object using the below snippet in your Junit for the import  com.adobe.granite.asset.api.Asset.

 // to create an asset
     AssetManager assetManager = resolver.adaptTo(AssetManager.class);
     Asset newAsset = assetManager.createAsset("/path/to/asset/document.pdf");

     // to get an existing asset
     Asset asset = assetManager.getAsset("/path/to/asset/document.pdf");

     // to get asset by adapting
     Asset asset = resource.adaptTo(Asset.class);
 

Asset properties can be retrieved or set by adapting it to a ValueMap.

     eg:
     // to get Asset properties value map
     ValueMap map = asset.adaptTo(ValueMap.class);

I hope this helps!!

Avatar

Level 2

Thank you for your reply @sravs 
But its giving NullPointerException at 

 Asset newAsset = assetManager.createAsset("/path/to/asset/document.pdf"); 

Avatar

Level 2
import javax.jcr.RepositoryException;

import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import com.adobe.granite.asset.api.Asset;
import com.adobe.granite.asset.api.AssetManager;
import com.adobe.granite.workflow.WorkflowException;


import io.wcm.testing.mock.aem.junit5.*;

@ExtendWith({ AemContextExtension.class, MockitoExtension.class })
class ExampleTest
{
    AemContext aemContext = new AemContext();

    @Mock
    Resource resource;

    @Mock
    ResourceResolver resolver;

    @BeforeEach
    void setup() throws Exception
    {
        aemContext.load().json("/com/example/test.json", "/content/dam");
    }

    @Test
    void testExecute() throws WorkflowException, RepositoryException {
        String resourcePath = "/content/dam/test.mp4";
        resource = aemContext.resourceResolver().getResource(resourcePath);

        AssetManager assetManager=resolver.adaptTo(AssetManager.class);// this is null
        Asset newAsset=assetManager.createAsset("/content/dam/test.mp4"); //getting the NPE Error

        //to get an existing assets
        Asset asset=assetManager.getAsset("/content/dam/test.mp4");
    }

}
 
 
///////////////////////////

JsonFile

{

"test.mp4":

{

"jcr:primaryType":"dam:Asset",

"jcr:createdBy":"admin"

}

}

Avatar

Community Advisor

@VJain03 

 

The adaptTo is null, because the resource is not of type dam:Asset.

Similar discussion at: https://stackoverflow.com/questions/44807635/aem-junit-test-with-a-dam-asset


Aanchal Sikka

Avatar

Level 2

Thanks for the reply @aanchal-sikka 

Here the resoure is of type dam:Asset
and i have checked 

DamUtil.isAsset(resource);

and its returning true

but for 

Asset asset = resource.adaptTo(Asset.class);

System.out.println(asset.getPath()); // Output: asset path: null 

if the Asset is imported from "import com.day.cq.dam.api.Asset;" then its adapting properly
but when Asset is imported from "import com.adobe.granite.asset.api.Asset;" then its giving null
request you to please solve this

Avatar

Community Advisor

There are 2 ways to "mock" this type of "Asset.class", what I've read so far in your replies is that you are mixing both. Here are the options:

1) You use a mocked resourceResolver and then you must mock each method that will be invoked by this object (especially the adapTo) and manually return another mock object, and the cycle repeats.

2) You use aemContext.resourceResolver() and configure it to be adapted to a AssetManager.class, 

My recommendation would be to go with method #2.

Usually, you would do something like this:

@Mock
private AssetManager mockAssetManager;

private AemContext context = new AemContext();

@BeforeEach
void setUp() {
   MockitoAnnotations.openMocks(this);
  //This will register the adapTo(AssetManager)
   context.registerAdapter(ResourceResolver.class, AssetManager.class, mockAssetManager);
}

@Test
void test_example() {
  Asset asset = context.resourceResolver().getResource("/path/to/your/asset").adaptTo(Asset.class);
  when(AssetManager.getAsset("/path/to/your/asset")).thenReturn(asset);
}

 

Check these references:

https://medium.com/@jlanssie/create-a-custom-workflow-model-in-aem-with-a-full-code-coverage-unit-te...

https://taylor.callsen.me/unit-testing-aem-sling-models-and-servlets/

 

Hope this helps



Esteban Bustamante

Avatar

Level 2

Thank you for your reply @EstebanBustamante 
Below code is giving null 
please check it

public class WorkflowTest {
    @Mock
    AssetManager mockAssetManager;
    private AemContext aemContext=new AemContext();
    @BeforeEach
    public void setup()
    {
    MockitoAnnotations.openMocks(this);
    aemContext.registerAdapter(ResourceResolver. class, AssetManager. class, mockAssetManager);
    aemContext.load().json("/com/test.json","/content");
}
    @Test
    public void test_example()
    {
  Asset asset=aemContext.resourceResolver().getResource("/content/test.mp4").adaptTo(Asset.class);   //Null if we use import "import com.adobe.granite.asset.api.Asset" but notNull if we use import "import com.day.cq.dam.api.Asset;"
    assertNotNull(asset);
    when(mockAssetManager.getAsset("content/test.mp4"))thenReturn(asset);  
}
}
request you to please solve this error

Avatar

Correct answer by
Community Advisor

Correct. It will return null if you use the com.adobe.granite.asset.api.Asset because it is not adaptable. Why are you using that? You should use the Asset implementation from com.day.cq.dam.api.Asset.

If you really want to stick with the other Asset implementation, you need to mock that class and not rely on the aemContext object. That's what I suggested as option #1 in my previous response. You should mock all of the following objects: ResourceResolver, the AdaptTo method, the AssetManager, and the Asset. The drawback with this approach is that you are not testing anything because you are setting the expected value at each step. So the best solution is to use the correct Asset implementation.

 

Hope this helps

 

 



Esteban Bustamante

Avatar

Level 2

Thanks For your Reply @EstebanBustamante 
In our project we are using "com.adobe.granite.asset.api.Asset" and we were told to use this api only as this is the latest one.