Expand my Community achievements bar.

SOLVED

Junit test cases for AEM Event Listener

Avatar

Level 2

Hello Everyone,

I need to write the junit for Event Listener. Attaching the sample code for reference. Could you please suggest the best way of writing the junit for Event Listener.

 

 

 

package myproject.core.listeners;

import java.util.HashMap;
import java.util.Map;

import javax.jcr.Node;
import javax.jcr.RepositoryException;

import javax.jcr.Session;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventListener;

import org.osgi.service.component.annotations.Activate;

import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;

import org.osgi.service.component.annotations.Reference;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.commons.Externalizer;
import myproject.core.service.EmailService;

import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.osgi.service.component.ComponentContext;
import javax.jcr.observation.EventIterator;

@component(immediate = true, service = EventListener.class)

public class UserNotificationListener implements EventListener {

Logger log = LoggerFactory.getLogger(this.getClass());
private Session adminSession;

String nodePath = StringUtils.EMPTY;

@reference
org.apache.sling.jcr.api.SlingRepository repository;

@reference
private ResourceResolverFactory resourceResolverFactory;

@reference
Externalizer externalizer;

@reference
private transient EmailService emailService;

@activate
public void activate(ComponentContext context) throws Exception {
log.info("activating ExampleObservation");
try {
adminSession = repository.loginService("datawrite", null);
adminSession.getWorkspace().getObservationManager().addEventListener(
this, //handler
Event.PROPERTY_ADDED | Event.NODE_ADDED, //binary combination of event types
"/home/users", //path
true, //is Deep?
null, //uuids filter
null, //nodetypes filter
false);

} catch(RepositoryException e) {
log.error("unable to register session", e);
throw new Exception(e);
}
}@Deactivate
public void deactivate() {
if (adminSession != null) {
adminSession.logout();
}
}

public void onEvent(EventIterator eventIterator) {
try {
while (eventIterator.hasNext()) {
Event event = eventIterator.nextEvent();
nodePath = event.getPath();
if (nodePath != null && nodePath.contains("email")) {
Node root = adminSession.getRootNode();
String profilepath = nodePath.substring(1, nodePath.lastIndexOf("/"));
log.info("profilepath path : {}", profilepath);
String externalurlprefix = profilepath.substring(0, profilepath.lastIndexOf("/"));
Node user_node = root.getNode(externalurlprefix);
String userName =user_node.getProperty("rep:principalName").getString();
// log.info("user_node userName" + user_node.getProperty("rep:principalName").getString());
// log.info("user_node password" + user_node.getProperty("rep:password").getString());
Node another_node = root.getNode(profilepath);
String emailAddress =another_node.getProperty("email").getString();
log.info("EmailId Node" + another_node.getProperty("email").getString());
ResourceResolver resourceResolver = null;
Map < String,Object > paramMap = new HashMap < String,Object > ();
// paramMap.put(ResourceResolverFactory.SUBSERVICE, "socialService");
paramMap.put(ResourceResolverFactory.SUBSERVICE, "datawrite");
resourceResolver = resourceResolverFactory.getServiceResourceResolver(paramMap);
String myExternalizedUrl = externalizer.authorLink(resourceResolver, "/libs/granite/security/content/v2/usereditor") + ".html/" + externalurlprefix;
Map < String,
String > emailParams = new HashMap < String,
String > ();
emailParams.put("userName", userName);
emailParams.put("recipient", emailAddress);
emailParams.put("emailSubject", "You’ve been invited to join the Intuit Asset Library.");
emailParams.put("message", "You’ve been invited to join the asset library.");
emailParams.put("passwordLinksHTML", myExternalizedUrl);
String recipientEmail = emailService.sendMail(resourceResolver, emailParams, emailAddress);
if (StringUtils.isEmpty(recipientEmail)) {
log.info("mail not sent");
} else {
log.info("mail sent successfully");
}

}

}

} catch(Exception e) {
log.error("Error while treating events", e);

}
}
}

1 Accepted Solution

Avatar

Correct answer by
Employee

The cleanest way to unit test this is to simply test is an OSGi service using AEM Mocks [1]  (which are a super-set of Sling Mocks/JCR mocks [2]).

You can see how something (of similar complexity, though a servlet) is achieved via this unit test [3]

Basically you'll need to:

 

1. Create a Unit Test using Mockito and AEM Mocks

2. In the @Before method

  • Define the testing node structure in a JSON file and load it into the mock text context 
  • Mock the AEM Externalizer service (I don't think AEM Mocks provide this, if they do then you don't have to mock it)
  • Register an instance of YOUR emailService as an OSGI service with the mock OSGi context (youll of course have to make sure any referenced OSGi service as satisfied too -- if this sends you down a rabbit hole, you can just mock your own EmailService and register that mock with the mock OSGi context
  • The other @References should be satisfied by AEM Mocks I think (SlingRepository, ResourceResolverFactory)

2. In your test case, injectAndActivate an instance of your EventListener along w/ any OSGi config properties you want to test it with)

3. Then, using the OSGi mock context get that service back using the interface (you can optionally cast the service to your impl class if you want to discretely test methods that arent on the interface).

4. Then you can test the service.

 

Note that as mentioned on [2] - with JcrMocks "Observation events can be registered but are ignored" - so looks like you'll mock that context when you test onEvent(..).

 

FWIW I think you'll end up spending some time getting it all mocked up/tested -- you may find that you want to refactor your code to be more testable as well.

 

[1] https://wcm.io/testing/aem-mock/

[2] https://sling.apache.org/documentation/development/jcr-mock.html

[3] https://github.com/Adobe-Marketing-Cloud/asset-share-commons/blob/develop/core/src/test/java/com/ado...

View solution in original post

3 Replies

Avatar

Community Advisor

@RunWith(PowerMockRunner.class)
@PrepareForTest({UserNotificationListener.class})
public class UserNotificationListenerTest {

@InjectMocks
private UserNotificationListener userNotificationListener;

@Mock
private SlingRepository repository;

@test
public void testActivate() throws Exception {

// get details here for activate
Session session = mock(Session.class);
Workspace workspace = mock(Workspace.class);
ObservationManager observationManager = mock(ObservationManager.class);

when(repository.loginService(JcrSessionService.QUERY_SESSION_SERVICE.getService(), null)).thenReturn(session);
when(repository.getDescriptor(Repository.OPTION_OBSERVATION_SUPPORTED)).thenReturn("true");
when(session.getWorkspace()).thenReturn(workspace);
when(workspace.getObservationManager()).thenReturn(observationManager);

userNotificationListener.activate();

verify(observationManager).addEventListener(userNotificationListener, <<<Event.NODE_ADDED>>>, "/<<PATH>>/", true, null, types, true);

}

@test
public void testDeactivate() throws Exception {

// get details here for activate
Session session = mock(Session.class);
Workspace workspace = mock(Workspace.class);
ObservationManager observationManager = mock(ObservationManager.class);

when(repository.loginService(JcrSessionService.QUERY_SESSION_SERVICE.getService(), null)).thenReturn(session);
when(repository.getDescriptor(Repository.OPTION_OBSERVATION_SUPPORTED)).thenReturn("true");
when(session.getWorkspace()).thenReturn(workspace);
when(workspace.getObservationManager()).thenReturn(observationManager);

userNotificationListener.deactivate();

verify(<<<>>>>);
}

@test
public void testOnEvent() throws Exception {
EventIterator eventIterator = mock(EventIterator.class);
when(eventIterator.hasNext()).thenReturn(true).thenReturn(false);

Event event = mock(Event.class);
when(eventIterator.nextEvent()).thenReturn(event);
<<<<< remaining steps >>>>
}
}

Avatar

Correct answer by
Employee

The cleanest way to unit test this is to simply test is an OSGi service using AEM Mocks [1]  (which are a super-set of Sling Mocks/JCR mocks [2]).

You can see how something (of similar complexity, though a servlet) is achieved via this unit test [3]

Basically you'll need to:

 

1. Create a Unit Test using Mockito and AEM Mocks

2. In the @Before method

  • Define the testing node structure in a JSON file and load it into the mock text context 
  • Mock the AEM Externalizer service (I don't think AEM Mocks provide this, if they do then you don't have to mock it)
  • Register an instance of YOUR emailService as an OSGI service with the mock OSGi context (youll of course have to make sure any referenced OSGi service as satisfied too -- if this sends you down a rabbit hole, you can just mock your own EmailService and register that mock with the mock OSGi context
  • The other @References should be satisfied by AEM Mocks I think (SlingRepository, ResourceResolverFactory)

2. In your test case, injectAndActivate an instance of your EventListener along w/ any OSGi config properties you want to test it with)

3. Then, using the OSGi mock context get that service back using the interface (you can optionally cast the service to your impl class if you want to discretely test methods that arent on the interface).

4. Then you can test the service.

 

Note that as mentioned on [2] - with JcrMocks "Observation events can be registered but are ignored" - so looks like you'll mock that context when you test onEvent(..).

 

FWIW I think you'll end up spending some time getting it all mocked up/tested -- you may find that you want to refactor your code to be more testable as well.

 

[1] https://wcm.io/testing/aem-mock/

[2] https://sling.apache.org/documentation/development/jcr-mock.html

[3] https://github.com/Adobe-Marketing-Cloud/asset-share-commons/blob/develop/core/src/test/java/com/ado...

Avatar

Community Advisor

you can try like this

 

public class UserNotificationListener implements EventListener {


@RunWith(PowerMockRunner.class)
@PrepareForTest({UserNotificationListener.class})
public class UserNotificationListenerTest {

@InjectMocks
private UserNotificationListener userNotificationListener;

@Mock
private SlingRepository repository;

@test
public void testActivate() throws Exception {

// get details here for activate
Session session = mock(Session.class);
Workspace workspace = mock(Workspace.class);
ObservationManager observationManager = mock(ObservationManager.class);

when(repository.loginService(JcrSessionService.QUERY_SESSION_SERVICE.getService(), null)).thenReturn(session);
when(repository.getDescriptor(Repository.OPTION_OBSERVATION_SUPPORTED)).thenReturn("true");
when(session.getWorkspace()).thenReturn(workspace);
when(workspace.getObservationManager()).thenReturn(observationManager);

userNotificationListener.activate();

verify(observationManager).addEventListener(userNotificationListener, <<<Event.NODE_ADDED>>>, "/<<PATH>>/", true, null, types, true);

}

@test
public void testDeactivate() throws Exception {

// get details here for activate
Session session = mock(Session.class);
Workspace workspace = mock(Workspace.class);
ObservationManager observationManager = mock(ObservationManager.class);

when(repository.loginService(JcrSessionService.QUERY_SESSION_SERVICE.getService(), null)).thenReturn(session);
when(repository.getDescriptor(Repository.OPTION_OBSERVATION_SUPPORTED)).thenReturn("true");
when(session.getWorkspace()).thenReturn(workspace);
when(workspace.getObservationManager()).thenReturn(observationManager);

userNotificationListener.deactivate();

verify(<<<>>>>);
}

@test
public void testOnEvent() throws Exception {
EventIterator eventIterator = mock(EventIterator.class);
when(eventIterator.hasNext()).thenReturn(true).thenReturn(false);

Event event = mock(Event.class);
when(eventIterator.nextEvent()).thenReturn(event);
<<<<< remaining steps >>>>
}
}