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\"}");
}
}
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\"}");
}
}
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.
I already stubbed content using context.create() , why I could not just have resource resolver read context content and not get this exception.
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();
}
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.
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)
Views
Replies
Total Likes
Views
Like
Replies