Expand my Community achievements bar.

Don’t miss the AEM Skill Exchange in SF on Nov 14—hear from industry leaders, learn best practices, and enhance your AEM strategy with practical tips.

session object in unit test

Avatar

Level 7

I am trying to write test cases for below existing code.  Test a node exists, if node exists get a node property and return. Nodes and properties will be created with AemContext.

 

 

 

Session session = resourceResolver.adaptTo(Session.class);
        	Node mfDataNode = null;
        	
			if(session.nodeExists(jcrPath+ "/" + dataPath))
			{
				
				mfDataNode = session.getNode(jcrPath+ "/" + dataPath);
				jsonData = mfDataNode.getProperty("reform-data").getString();
			}

 

 

 

I tried below test code but session returned is mock session instance and session.nodeExists always comes false.

Any help , how to test above piece of code.

Below is source code, unit test code written so far.

 

Here is the complete servlet source code:

 

 

(
		service = Servlet.class,
		name = "Reform Servlet",
		property = {
				"sling.servlet.paths=" + "/bin/reform-message",
				"sling.servlet.methods=" + HttpConstants.METHOD_GET
		}
)

public class ReformServlet extends SlingAllMethodsServlet implements Serializable {

	private static final long serialVersionUID = 1L;
	private static final Logger log = LoggerFactory.getLogger(ReformServlet.class);
    
    
    private ConfigurationAdmin configAdmin;

    
    private ResourceResolverFactory resolverFactory;

    
    protected void doGet(final SlingHttpServletRequest request, final SlingHttpServletResponse response) 
    		throws ServletException,IOException 
    {
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();

    	try 
    	{	
    		log.info("ReformServlet.doGet");
    		
    		out.write( getMessage());
    		
    	}
    	catch (Exception ex)
    	{
    		{
    			response.setStatus(500);
    			out.write("doGet - ReformServlet");
    		}
    	}
    }

        
    private String getMessage()
    {
        //servlet returns JSON string
        String jsonData = null;
        ResourceResolver resourceResolver = null;
        
        try 
        {
        	String jcrPath = getProperty("/cotent/test");
        	String dataPath = getProperty("reform-cache");
        	
        	java.util.Map<String, Object> param = new java.util.HashMap<String, Object>();
	    	
	    	param.put(ResourceResolverFactory.USER, Constants.ConfigProperties.ISG_SYSTEM_USER);

	    	resourceResolver = resolverFactory.getServiceResourceResolver(param);
	    	
			Session session = resourceResolver.adaptTo(Session.class);
        	Node mfDataNode = null;
        	
			if(session.nodeExists(jcrPath + "/" + dataPath))
			{
				
				mfDataNode = session.getNode(jcrPath+ "/" + dataPath);
				jsonData = mfDataNode.getProperty("reform-data").getString();
			}
			else
			{
				log.error("data DOES NOT exist");
			}
        } 
        catch (Exception e) 
        {
			log.error("data - caught exception", e);
        }
        finally
        {
        	try { resourceResolver.close(); } catch(Throwable t) {}
        }
        
        return jsonData;
    }
    
	
	protected String getProperty(String key) 
			throws Exception
	{
		
		String property = null;
		try
		{
			Configuration config = (Configuration) configAdmin
					.getConfiguration(Constants.ConfigProperties.OSGI_CONFIG_NAME);
			
			Dictionary props = config.getProperties();
						
			property = (String)props.get(key);
			
			
		}
		catch(Exception e)
		{
			log.error("getProperty - caught exception getting property {}", key);
			throw(e);
		}
		
		return property;			
		

	}

}

 

 

 

 

Here is the test class written so far:

 

 

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

    @InjectMocks
    private ReformServlet fixture = new ReformServlet();

    @Mock
    private ConfigurationAdmin configAdmin;

    @Mock
    private ResourceResolverFactory resolverFactory;



    @BeforeEach
    void setUp(AemContext context) throws IOException {

        MockitoAnnotations.initMocks(this);

        context.create().resource("/content/test", ImmutableMap.<String, Object>builder()
                .put("jcr:title", "test page")
                .build());
        context.create().resource("/content/test/reform-cache", ImmutableMap.<String, Object>builder()
                .put("jcr:title", "reform cache")
                .build());

        context.registerService(ConfigurationAdmin.class, configAdmin);
        context.registerService(ResourceResolverFactory.class, resolverFactory);

        ConfigurationAdmin configAdmin = context.getService(ConfigurationAdmin.class);

    }

 

    
    void doGet(AemContext context) throws ServletException, IOException, LoginException {


        context.currentResource("/content/test");

        MockSlingHttpServletRequest request = context.request();
        MockSlingHttpServletResponse response = context.response();

        Configuration configurationMock = Mockito.mock(Configuration.class);

        Mockito.when(configAdmin.getConfiguration(Mockito.anyString())).thenReturn(configurationMock);
        Mockito.when(configurationMock.getProperties()).thenReturn(new Hashtable<String, Object>(){{
            put("jcrPath", "/content/test");
            put("dataPath", "reform-cache");
        }});

        Mockito.when(resolverFactory.getServiceResourceResolver(Mockito.anyMap())).thenReturn(context.resourceResolver());
        Session mockSession = Mockito.mock(Session.class);
        context.registerAdapter(ResourceResolver.class, Session.class, mockSession);

        fixture.doGet(request, response);



    }


}

 

 

UPDATE:

I have update unit test code to use JCR_MOCK resource resolver type.

Getting error 

java.lang.IllegalStateException: Resource resolver is already closed.

at org.apache.sling.resourceresolver.impl.ResourceResolverImpl.checkClosed(ResourceResolverImpl.java:186)
at org.apache.sling.resourceresolver.impl.ResourceResolverImpl.adaptTo(ResourceResolverImpl.java:807)
at org.apache.sling.testing.mock.sling.context.SlingContextImpl.tearDown(SlingContextImpl.java:225)
at io.wcm.testing.mock.aem.context.AemContextImpl.tearDown(AemContextImpl.java:105)

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


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

    @InjectMocks
    private MoneyMarketReformServlet fixture = new MoneyMarketReformServlet();

    @Mock
    private ConfigurationAdmin configAdmin;

    @Mock
    private ResourceResolverFactory resolverFactory;

    @Mock
    private ResourceResolver leakedResourceResolver;

    @BeforeEach
    void setUp() throws IOException {

        MockitoAnnotations.initMocks(this);

        context.create().resource("/content/test", ImmutableMap.<String, Object>builder()
                .put("jcr:title", "test page")
                .build());
        context.create().resource("/content/test/reform-cache", ImmutableMap.<String, Object>builder()
                .put("jcr:title", "reform cache")
                .put("messageData", "{\"globalMessage\":\"some message\"}")
                .build());

      //  context.registerService(ConfigurationAdmin.class, configAdmin);
      //  context.registerService(ResourceResolverFactory.class, resolverFactory);

    }

    @test
    void doGet() throws ServletException, IOException, LoginException {


        context.currentResource("/content/test");

        MockSlingHttpServletRequest request = context.request();
        MockSlingHttpServletResponse response = context.response();

        Configuration configurationMock = Mockito.mock(Configuration.class);

        Mockito.when(configAdmin.getConfiguration(Mockito.anyString())).thenReturn(configurationMock);
        Mockito.when(configurationMock.getProperties()).thenReturn(new Hashtable<String, Object>(){{
            put("jcrPath", "/content/test");
            put("dataPath", "reform-cache");
        }});

        Mockito.when(resolverFactory.getServiceResourceResolver(Mockito.anyMap())).thenReturn(Mockito.spy(context.resourceResolver()));
      //  Session mockSession = Mockito.mock(Session.class);
      //  context.registerAdapter(ResourceResolver.class, Session.class, mockSession);

        fixture.doGet(request, response);


        assertEquals(response.getOutputAsString(), "{\"globalMessage\":\"some message\"}");

    }


}

 

7 Replies

Avatar

Level 7

Made couple of changes :

//USING JCR_MOCK resource resolver type
private final AemContext context = new AemContext(ResourceResolverType.JCR_MOCK);

 

and

Mockito.when(resolverFactory.getServiceResourceResolver(Mockito.anyMap())).thenReturn(Mockito.spy(context.resourceResolver()));

 

below is latest unit test code, this is almost working, and throwing "resource resolver is already closed" by AemContext 

 

java.lang.IllegalStateException: Resource resolver is already closed.

	at org.apache.sling.resourceresolver.impl.ResourceResolverImpl.checkClosed(ResourceResolverImpl.java:186)
	at org.apache.sling.resourceresolver.impl.ResourceResolverImpl.adaptTo(ResourceResolverImpl.java:807)
	at org.apache.sling.testing.mock.sling.context.SlingContextImpl.tearDown(SlingContextImpl.java:225)
	at io.wcm.testing.mock.aem.context.AemContextImpl.tearDown(AemContextImpl.java:105)
	at io.wcm.testing.mock.aem.junit5.AemContext.tearDownContext(AemContext.java:107)
	at io.wcm.testing.mock.aem.junit5.AemContextExtension.lambda$afterEach$3(AemContextExtension.java:152)
	at io.wcm.testing.mock.aem.junit5.AemContextExtension.applyAemContext(AemContextExtension.java:180)
	at io.wcm.testing.mock.aem.junit5.AemContextExtension.afterEach(AemContextExtension.java:147)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeAfterEachCallbacks$12(TestMethodTestDescriptor.java:233)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeAllAfterMethodsOrCallbacks$14(TestMethodTestDescriptor.java:245)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeAllAfterMethodsOrCallbacks(TestMethodTestDescriptor.java:243)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeAfterEachCallbacks(TestMethodTestDescriptor.java:232)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:133)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
	at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
	at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)

 

//code thatis doing resolver close in servlet

finally
{
try { resourceResolver.close(); } catch(Throwable t) {}
}

 

 

 

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

   //USING JCR_MOCK resource resolver type
    private final AemContext context = new AemContext(ResourceResolverType.JCR_MOCK);

    @InjectMocks
    private ReformServlet fixture = new ReformServlet();

    @Mock
    private ConfigurationAdmin configAdmin;

    @Mock
    private ResourceResolverFactory resolverFactory;



    @BeforeEach
    void setUp() throws IOException {

        MockitoAnnotations.initMocks(this);

        context.create().resource("/content/test", ImmutableMap.<String, Object>builder()
                .put("jcr:title", "test page")
                .build());
        context.create().resource("/content/test/reform-cache", ImmutableMap.<String, Object>builder()
                .put("jcr:title", "reform cache")
                .put("mmrMessageData", "{\"globalMessage\":\"some message\"}")
                .build());

      //  context.registerService(ConfigurationAdmin.class, configAdmin);
      //  context.registerService(ResourceResolverFactory.class, resolverFactory);

    }

    
    void doGet() throws ServletException, IOException, LoginException {

        context.currentResource("/content/test");

        MockSlingHttpServletRequest request = context.request();
        MockSlingHttpServletResponse response = context.response();

        Configuration configurationMock = Mockito.mock(Configuration.class);

        Mockito.when(configAdmin.getConfiguration(Mockito.anyString())).thenReturn(configurationMock);
        Mockito.when(configurationMock.getProperties()).thenReturn(new Hashtable<String, Object>(){{
            put("jcrPath", "/content/test");
            put("dataPath", "reform-cache");
        }});
        
        Mockito.when(resolverFactory.getServiceResourceResolver(Mockito.anyMap())).thenReturn(Mockito.spy(context.resourceResolver()));
      //  Session mockSession = Mockito.mock(Session.class);
      //  context.registerAdapter(ResourceResolver.class, Session.class, mockSession);

        fixture.doGet(request, response);

        assertEquals(response.getOutputAsString(), "{\"globalMessage\":\"some message\"}");

    }
}

 

 

 

Avatar

Level 4

Hi @sreenu539 ,

 

Can you try to mock Session object like 

@Mock
Session session;

and use lenient when try to return object like:

lenient().when().then(session.nodeExits("path"))Return(true);

It worked for me.

Avatar

Level 7

I already stubbed content using context.create() , why I could not just have resource resolver read context content and not get this exception.

Avatar

Level 7

I just need to write unit test for some thing like this. Even this kind of style code is failing with Resourceresolver is alredy closed exception. 

 

try (ResourceResolver resolver = factory.getServiceResourceResolver(authInfo)) {
    Resource resource = resolver.getResource("/content/sourcedcode/jcr:content");
    if (Objects.nonNull(resource)) {
//read resource data
    }
} catch (Exception e) {
    e.printStackTrace();
}

 

Avatar

Level 4

try to use lenient methods when using stubbed objects. If there is any dependency injected at the start of the code, you can use @BeforeEach annotation in method to set the dependencies in the starting of the execution.

Avatar

Level 1

Instead of ResourceResolverType.JCR_MOCK you could try using:

AemContext context = new AemContext(ResourceResolverType.JCR_OAK);

This type of AemContext should pretty much work as if there was actual JCR, in fact if I recall correctly, it creates a JCR tree in-memory. I believe it could be working on an actual Session instance, not a MockSession.

@sreenu539 you can pass cloned resource resolver 

aemContext.resourceResolver().clone(null)