May 4, 2020
Estimated Post Reading Time ~

Unit Testing WCMUse Classes using Mockito

Developers know testing code is important, and one of the best ways to do so is through unit tests. One of the questions preventing developers from writing unit tests, in Adobe Experience Manager development, is the question: how can I start writing tests, when required classes are only available in the context of a running AEM instance, that won’t fail because of a null pointer?

I found a simple solution, for a simple case that has promise to also cover some more complicated scenarios. The solutions involve using Mockito to mock objects and provide test return values for methods in classes not available outside the context of AEM.

Example WCMUse Class
package com.aempodcast.example.components;

import com.adobe.cq.sightly.WCMUse;
import org.apache.sling.api.resource.ValueMap;

public class Example extends WCMUse {

    private String title;
    private String type;
    
    @Override
    public void activate() {
        ValueMap properties = getProperties();
        title = properties.get("title", "");
        type = properties.get("type", "");
    }

    public String getTitle() {
        return title;
    }

    public String getType() {
        return type;
    }
}

Example Test Class
package com.aempodcast.example.components;
 
import java.util.HashMap;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.ValueMapDecorator;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
 
public class ExampleTest {
 
    private Example example;
    private ValueMap properties;
 
    public ExampleTest() {
        // Create a mock of the WCMUse class.
        example = mock(Example.class);
 
        // Create test objects for mocking (properties ValueMap in this case).
        properties = new ValueMapDecorator(new HashMap());
 
        // Set what to use when superclass methods are called.
        when(example.getProperties()).thenReturn(properties);
 
        // Set to call the real methods in the class being tested. For methods that return something.
        when(example.getTitle()).thenCallRealMethod();
        when(example.getType()).thenCallRealMethod();
 
        // Set to call the real activate method in the class being tested. For void return types.
        doCallRealMethod().when(example).activate();
    }
 
    // Write tests
    @Test
    public void testGetTitle() {
        String testTitle = "test title";
        properties.put("title", testTitle);
        example.activate();
        String title = example.getTitle();
        assertEquals(testTitle, title);
    }
 
    @Test
    public void testGetType() {
        String testType = "test type";
        properties.put("type", testType);
        example.activate();
        String type = example.getType();
        assertEquals(testType, type);
    }
 
}

Conclusion
Writing tests for WCMUse classes, for the simple example, was easier than I expected. All that needs to be done to set up the test class for testing WCMUse classes are:
  1. Create a mockup of the WCMUse class being tested.
  2. Create objects used for testing (i.e., properties map).
  3. Configure the mock object to do what is needed for the methods used.
  • Return the value needed for the test.
  • Call the actual method.
   4. Write the tests.
Here are some references for mocked objects for testing code used in AEM:
OSGi: http://sling.apache.org/documentation/development/osgi-mock.html
JCR: http://sling.apache.org/documentation/development/jcr-mock.html
Sling: http://sling.apache.org/documentation/development/sling-mock.html



By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.