Expand my Community achievements bar.

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)