Expand my Community achievements bar.

Applications for the 2024-2025 Adobe Experience Manager Champion Program are open!
SOLVED

JUnit testing fails for `session.save()` with error "Wanted but not invoked:"

Avatar

Level 3

I am trying to create a unit test that checks whether `session.save();` has been called, in my service implementation below:

 

TagManagerServiceImpl.java

@component(service = TagManagerService.class, immediate = true)
public class TagManagerServiceImpl implements TagManagerService {
    private static final Logger LOGGER = LoggerFactory.getLogger(TagManagerServiceImpl.class);
    @reference
    private ResourceResolverFactory resolverFactory;
    @reference
    private JcrTagManagerFactory jcrTagManagerFactory;

    public void createTag(String tagPath, String tagTitle, String tagDescription) {
        ResourceResolver resourceResolver = null;

        try {
            resourceResolver = ResolverUtil.newResolver(resolverFactory);

            Session session = resourceResolver.adaptTo(Session.class);

            TagManager tagManager = jcrTagManagerFactory.getTagManager(session);

            if (session != null) {
                tagManager.createTag(tagPath, tagTitle, tagDescription, true);
                session.save(); //<========== want to test this
            }

        } catch (Exception e) {
            LOGGER.error("Error while creating tag", e);
        } finally {
            if (resourceResolver != null && resourceResolver.isLive()) {
                resourceResolver.close();
            }
        }
    }
}

 

My JUnit test is as follow:

 

TagManagerServiceTest.java

@ExtendWith(MockitoExtension.class)
public class TagManagerServiceTest {
    @InjectMocks
    private TagManagerServiceImpl tagManagerService;
    @Mock
    private ResourceResolverFactory resolverFactory;
    @Mock
    private JcrTagManagerFactory jcrTagManagerFactory;
    @Mock
    private Session session;
    @Mock
    private TagManager tagManager;
    @Mock
    private ResourceResolver resourceResolver;

    @BeforeEach
    public void setUp() {
        MockitoAnnotations.initMocks(this);

        try {
            when(ResolverUtil.newResolver(resolverFactory)).thenReturn(resourceResolver);
            when(resourceResolver.adaptTo(Session.class)).thenReturn(session);
            when(jcrTagManagerFactory.getTagManager(session)).thenReturn(tagManager);
        } catch (Exception e) {
            fail("Expected no exceptions, but got: " + e.getMessage());
        }
    }

    @test
    public void testCreateTag() {
        String tagPath = "some/tagPath";
        String tagTitle = "TagTitle";
        String tagDescription = "TagDescription";

        tagManagerService.createTag(tagPath, tagTitle, tagDescription);

        try {
            verify(tagManager, times(1)).createTag(tagPath, tagTitle, tagDescription, true);

            System.out.println(mockingDetails(session).printInvocations()); // No interactions and stubbings found for mock: session

            verify(session, times(1)).save(); // <========= testing session.save();

        } catch (Exception e) {
            fail("Expected no exceptions, but got: " + e.getMessage());
        }
    }
}

 

 

But when I run the test, I get the following error. The line 66 mentioned being `verify(session, times(1)).save();` in the above code.

Wanted but not invoked:
session.save();
-> at com.mysite.core.services.TagManagerServiceTest.testCreateTag(TagManagerServiceTest.java:66)
Actually, there were zero interactions with this mock.

 

As you can see in my test code, I troubleshot by placing `System.out.println(mockingDetails(session).printInvocations());` right before the test, and got the printed message "No interactions and stubbings found for mock: session".

 

How can I make sure that `session.save();` is property tested?

 

Thanks,

1 Accepted Solution

Avatar

Correct answer by
Employee

@sean12341 

Please go through the link below. it will help to setup Junit testing framework.

https://experienceleague.adobe.com/docs/experience-manager-learn/getting-started-wknd-tutorial-devel...

Once done you can refer the below link to check how to test session.save() 

https://github.com/Adobe-Consulting-Services/acs-aem-commons/blob/master/bundle/src/test/java/com/ad...

 

 

View solution in original post

4 Replies

Avatar

Community Advisor

@sean12341 

 

I would suggest to use https://wcm.io/testing/ in the project. Its based on Sling and helps you test things more in AEM context than mocking it. So, the test cases of modifying/persisting things are more real.

 

With this set up, you can use assertFalse(session.hasPendingChanges()); to verify if the session.save() was called.


Aanchal Sikka

Avatar

Correct answer by
Employee

@sean12341 

Please go through the link below. it will help to setup Junit testing framework.

https://experienceleague.adobe.com/docs/experience-manager-learn/getting-started-wknd-tutorial-devel...

Once done you can refer the below link to check how to test session.save() 

https://github.com/Adobe-Consulting-Services/acs-aem-commons/blob/master/bundle/src/test/java/com/ad...

 

 

Avatar

Employee Advisor

I think your mocking is incorrect:

when(resourceResolver.adaptTo(Session.class)).thenReturn(session);

 

try this one:

when(resourceResolver.adaptTo(any(Session.class))).thenReturn(session);

 

Avatar

Level 4

Not sure why it's not called, but I have some concerns that you have the old initialization of mocks

 

MockitoAnnotations.initMocks(this);

 

together with 

 

@ExtendWith(MockitoExtension.class)

 

 

Also, this one:

 

when(ResolverUtil.newResolver(resolverFactory)).thenReturn(resourceResolver);

 

looks like mocking of a static method, shouldn't it be 

 

try (MockedStatic<ResolverUtil> resolverUtil = Mockito.mockStatic(ResolverUtil.class)) {
  resolverUtil.when(() -> ResolverUtil.newResolver(resolverFactory)))
          .thenReturn(resourceResolver);

  // all the other code that uses ResolverUtil.newResolver()
}

 

?

 

Are you sure your error "Error while creating tag" is not output in the maven output? Have you enabled simple logger or added the console output to your lidalia logger if you use it instead of the simple logger? I suppose there is NullPointerException actually on the line "resourceResolver.adaptTo..."