May 1, 2020
Estimated Post Reading Time ~

How to write Automated Test Cases for AEM Projects

In the software development lifecycle, testing plays a vital role with respect to quality assurance and quality control of any project. Automated testing saves a lot of time when building and releasing different versions of a project.

It becomes a tedious task for a QA team to do manual testing after each iteration for the same functionality repeatedly. In this post, I will share a few tips and tricks to writing test cases for different testing scenarios.


Specifically, let’s look at writing automated test cases for an AEM-based project. There are different modules in AEM: the core bundle, which includes OSGI services, sling servlets, ad sling models; and ui.apps, which includes AEM components, AEM pages, templates, and HTML markups.

As a project and codebase grow, it is really important to make sure that test coverage for the code is there to maintain consistency and sanity. Writing test cases for AEM is different from writing conventional Java test cases, and this can make it difficult for a beginner to write test cases for AEM application

Adobe Solution
AEM 6.5
Installation

  • jdk1.8 has to be installed in your system
  • Maven has to be installed in your system
  • AEM 6.5 author instance has to be running
Prerequisites

<dependencies>

    ...

    <!-- Testing -->
     <dependency>
         <groupId>org.junit</groupId>
         <artifactId>junit-bom</artifactId>
         <version>5.5.2</version>
         <type>pom</type>
         <scope>import</scope>
     </dependency>
     <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-simple</artifactId>
         <version>1.7.25</version>
         <scope>test</scope>
     </dependency>
     <dependency>
         <groupId>org.mockito</groupId>
         <artifactId>mockito-core</artifactId>
         <version>2.25.1</version>
         <scope>test</scope>
     </dependency>
     <dependency>
         <groupId>org.mockito</groupId>
         <artifactId>mockito-junit-jupiter</artifactId>
         <version>2.25.1</version>
         <scope>test</scope>
     </dependency>
     <dependency>
         <groupId>junit-addons</groupId>
         <artifactId>junit-addons</artifactId>
         <version>1.4</version>
         <scope>test</scope>
     </dependency>
     <dependency>
         <groupId>io.wcm</groupId>
         <artifactId>io.wcm.testing.aem-mock.junit5</artifactId>
         <!-- Prefer the latest version of AEM Mock Junit5 dependency -->
         <version>2.5.2</version>
         <scope>test</scope>
     </dependency>
    ...
</dependencies>

Below, you’ll see the plugins and dependencies that you need to add in pom.xml under core package i.e core/pom.xml

<plugin>

         <artifactId>maven-surefire-plugin</artifactId>

                <version>2.22.0</version>
                <configuration>
                    <includes>
                        <include>*Test.java</include>
                    </includes>
                    <skipTests>${skipTests}</skipTests>
                    <trimStackTrace>false</trimStackTrace>
                </configuration>
    </plugin>
--------------------------------------------------------------------
         <execution>
               <id>report</id>
                <phase>test</phase>
                <goals>
                    <goal>report</goal>
               </goals>
         </execution>
-------------------------------------------------------------------
...
     <dependency>
         <groupId>org.junit.jupiter</groupId>
         <artifactId>junit-jupiter</artifactId>
         <scope>test</scope>
     </dependency>
     <dependency>
         <groupId>org.mockito</groupId>
         <artifactId>mockito-core</artifactId>
         <scope>test</scope>
     </dependency>
     <dependency>
         <groupId>org.mockito</groupId>
         <artifactId>mockito-junit-jupiter</artifactId>
         <scope>test</scope>
     </dependency>
     <dependency>
         <groupId>junit-addons</groupId>
         <artifactId>junit-addons</artifactId>
     </dependency>
     <dependency>
         <groupId>io.wcm</groupId>
         <artifactId>io.wcm.testing.aem-mock.junit5</artifactId>
     </dependency>
     ...

Writing test cases for the generic helper class
This is the simplest use case; your generic helper class (for example, StringUtils, DateUtils) does not use any AEM libraries. For this, you can simply use Junit to write your unit test: https://www.tutorialspoint.com/junit.

Here, you need to use a @ Test annotation at the method level; for example, below I have added a @ Test annotation for the testIsEmpty() method, checking various scenarios using the assertTrue and assertFalse function by comparing expected value and actual value.

public class ExampleTest {



  @Test
  public void testIsEmpty() {
   assertTrue(CommonStringUtil.isEmpty(“”));
   assertFalse(CommonStringUtil.isEmpty(“ “));
  }
}

Writing test cases for AEM services
Now, this is where it gets a bit tricky, where you need to mock certain behaviors of the bundle and implicit objects. That’s why Sling has created a Mock version of sling objects and wcm.io has created a mock version of AEM objects. Here, you can just use aem mock: https://wcm.io/testing/aem-mock/usage.html to achieve most of your use cases (AEM mock extends Sling mock).

Below are some of the common use cases you will come across while testing your service:

1) How can I mock content my service is running against?
For this, it is recommended to use contentLoader API: http://wcm.io/testing/aem-mock/usage.html to either load existing json based resources (you can simply get it by creating a resource in CRXDE and then use something like RESOURCEPATH.infinity.json to get json for that resource) or just create a mock resource using ContentBuilder context.create().resource() or ResourceBuilder context.build().resource(): http://wcm.io/testing/aem-mock/apidocs/.

Note that if you are mocking a Page object then you have to use aem mock using aemcontext.pageManager().create()

2) How can I initialize properties in the bundle?
You can use register and activate the OSGI service with properties: http://wcm.io/testing/aem-mock/usage.html#Registering_OSGi_service. Here is an example using AEM context Junit5:

@ExtendWith(AemContextExtension.class)

public class ExampleTest {


  private final AemContext context = new AemContext();

  @Test
  public void testSomething() {
    Resource resource = context.resourceResolver().getResource("/content/sample/en");
    Page page = resource.adaptTo(Page.class);
    // further testing
  }

}

3) How can I inject other services for my service?
You can either Mock service or use a register service API for this: http://wcm.io/testing/aem-mock/usage.html#Registering_OSGi_service

Note that when you inject a service to your service using Reference then you will have to register your injected service, otherwise, your test will fail.

@ExtendWith(AemContextExtension.class)

@ExtendWith(MockitoExtension.class)

public class ExampleServiceTest {

 private final AemContext context = new AemContextBuilder().build();
@Mock
  BlogService blogService;
@Test
  public void testSomething() {
   context.load().json("/content/sample/en.json");
   context.registerService(BlogService.class,blogService);
Mockito.when(context.getService(BlogService.class).calledMethod(notNull).thenReturn("expectedString")
//further testing
}

}

4) How can I test a sling model?
You can use aemContext for this: http://wcm.io/testing/aem-mock/usage.html#Sling_Models.

@Before

public void setUp() {

  // register models from package
  context.addModelsForPackage("com.app1.models");
}

@Test
public void testSomething() {
  RequestAttributeModel model = context.request().adaptTo(RequestAttributeModel.class);
  // further testing
}

@Model(adaptables = SlingHttpServletRequest.class)
interface RequestAttributeModel {
  @Inject
  String getProp1();
}
//further testing

Writing test cases for AEM servlets
This is very similar to how you would do test cases for Service. For request and response, you either have to mock request/response object using Mockito or use Spy or use a sling request and response mock. Since a lot of methods in filter and servlet do not return any result, make Mockito verify your friend. Here is an example using simple Mockito to test a servlet:

@ExtendWith(AemContextExtension.class)

@ExtendWith(MockitoExtension.class)

public class ExampleServletTest {

 private final AemContext context = new AemContextBuilder().build();
@Mock
  UserService userService;
@Spy
  BlogService blogService = new BlogServiceImpl();
@InjectMocks
    ExampleServletTest exampleServlet = new ExampleServletTest();
@BeforeEach
  public void setUp() {
   context.load().json("/content/sample/en.json");
   context.registerService(UserService.class,userService);
   context.registerInjectActivateService(blogService);
}
 @Test()
 public void doGetmethod500error() throws IOException {
  Map<String, Object> parameters = new HashMap<>();
  parameters.put("projectId", "1234");
Mockito.when(context.getService(UserService.class).getUser("username")
    .thenReturn(new Response(errorResponseMsg, 500));
 MockSlingHttpServletRequest request = new MockSlingHttpServletRequest(context.resourceResolver(),
    context.bundleContext());
  MockSlingHttpServletResponse response = new MockSlingHttpServletResponse();
  request.setParameterMap(parameters);
  exampleServlet.doGet(request, response);
  String endResponseStr = response.getOutputAsString();
  assertNotNull(endResponseStr);
//further testing
}
}

Test cases execution
You need to open terminal with the working directory as your AEM project and will need to run this command: mvn clean test


By aem4beginner

No comments:

Post a Comment

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