Expand my Community achievements bar.

Dive into Adobe Summit 2024! Explore curated list of AEM sessions & labs, register, connect with experts, ask questions, engage, and share insights. Don't miss the excitement.
SOLVED

junit5 and Mockito tests not injecting the ResourceResolverFactory

Avatar

Level 3

I have been updating out code base with unit tests and they have some Sling servlets that are obtaining the service user based ResourceResolver for extra work and making calls to other services. The issue I'm having is that the servlet uses @reference ResourceResolverFactory resourceResolverFactory to obtain an instance of the factory. In my tests, I have tried AemContext.registerService(ResourceResolverFactory.class, resourceResolverInstance) to attempt to set the mocked factory. The servlet is not resolving the service so I am unable to perform a proper test.

I am using the mockito-core 3.3.3 , org.apache.sling.testing.osgi-mock.junit5 3.1.2, io.wcm.testing.aem-mock.junit5 3.0.2, mockito-junit-jupiter 3.3.3 dependencies. Many of the on line samples don't work with these versions because packaging and classes have changed.

 

Help with resources and what I need to do in order to get the @reference annotation to include the testing instance of the ResourceResolverFactory would be fantastic.

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

Hi @RobertHarper,

For the snippet that you have shared now, here is the Test class, you can use this as is and check if it works now. 

Changes done (on top of what you shared)

  • Mocked ResourceResolverFactory (via @Mock)
    • @Mock
      private ResourceResolverFactory rescResolverFactory;
  • Added MockitoExtension.class to @ExtendWith (for using @Mock)
    • @ExtendWith({AemContextExtension.class, MockitoExtension.class})
  • Removed the AemContext from doGet argument and instantiated explicitly with ResourceResolverType as RESOURCERESOLVER_MOCK
    • private AemContext context = new AemContext(ResourceResolverType.RESOURCERESOLVER_MOCK);
package com.mysite.core.servlets;

import java.io.IOException;

import javax.servlet.ServletException;

import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.testing.mock.sling.ResourceResolverType;
import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletRequest;
import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletResponse;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import io.wcm.testing.mock.aem.junit5.AemContext;
import io.wcm.testing.mock.aem.junit5.AemContextExtension;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.assertEquals;

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

    @Mock
    private ResourceResolverFactory resourceResolverFactory;

    private AemContext context = new AemContext(ResourceResolverType.RESOURCERESOLVER_MOCK);

    @InjectMocks
    private SimpleServlet fixture = new SimpleServlet();

    @Test
    void doGet() throws ServletException, IOException {
        context.build().resource("/content/test", "jcr:title", "resource title").commit();
        context.currentResource("/content/test");

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

        fixture.doGet(request, response);

        assertEquals("Title = resource title", response.getOutputAsString());
    }
}

Once when you see the above working, you can try the below. 

 

For creating ResourceResolver out of this mocked ResourceResolverFactory, we need to introduce when and thenReturn  

Map<String, Object> map = new HashMap<>();
map.put(ResourceResolverFactory.SUBSERVICE, "demoproject-service");
/* Getting Resolver from current AemContext */
ResourceResolver resourceResolver = context.request().getResourceResolver();
/*Using the resolver from previous step for thenReturn */
when(rescResolverFactory.getServiceResourceResolver(map)).thenReturn(resourceResolver);

Update : (Corrected the typo on variable name of mocked ResourceResolverFactory)

when(resourceResolverFactory.getServiceResourceResolver(map)).thenReturn(resourceResolver);

 

View solution in original post

24 Replies

Avatar

Employee Advisor

The mocked ResourceResolverFactory is not used in the test, so you should be able to remove it. 

Otherwise: +1

Avatar

Level 3

That was okay. The big thing was go see how to get the reference to resolve while testing. Once that worked, more code was written for the real test. If the ResourceResolverFactory had been omitted from the example, nothing would have been gained.

Avatar

Level 7

Above is returning below 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)
	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)


Process finished with exit code 255

 

 

Here is servlet, test class

 

 


@Component(
		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;

	@Reference
	private ResourceResolverFactory rFactory;

    
    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 -  Message ReformServlet");
    		}
    	}
    }

        
    private String getMessage()
    {
        //servlet returns JSON string
        String jsonData = "{}";

        try(ResourceResolver rSolver = ResourceResolverUtil.getResourceResolver(rFactory))
        {
		

        	String jcrPath = getProperty("jcrPath");
        	String datataPath = getProperty("dataPath");

			Resource mfDataNode = rSolver.getResource(jcrPath+ "/" + dataPath);
			if(mfDataNode != null){
				
				jsonData = mfDataNode.getValueMap().get("messageData",String.class);
			}
			else
			{
				log.error("data doesnot exist");
			}
        } 
        catch (Exception e) 
        {
			log.error("caught exception", e);
        }

        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("caught exception getting property {}", key);
			throw(e);
		}
		
		return property;			
		

	}

}

 

 

 

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


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

    @Mock
    private ConfigurationAdmin configAdmin;

    @Mock
    private ResourceResolverFactory resolverFactory;

    @InjectMocks
    private ReformServlet fixture = new ReformServlet();


    @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());

     
    }

    
    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(context.request().getResourceResolver());
     
        fixture.doGet(request, response);

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

    }


}