Understanding Junit5 usage in AEM 6.5.9 and AEMaaCs Java Classes | Archetype 27

As we all know that latest JUnit is 5 which is the next generation of JUnit. The goal is to create an up-to-date foundation for developer-side testing on the JVM. This includes focusing on Java 8 and above, as well as enabling many different styles of testing.

We will be using AEM best practices, and use (Adobe Recommended):


As we all know nowadays AEM archetype comes with inbuilt Junit5 dependencies.
So let’s understand what we get as part of AEM archetype 27 in terms of Junit 5.

NOTE: Below dependencies are OOTB with AEM Archetype 27 as tested.

1. Understanding the Dependencies and Plugins:

1.1 Required Dependencies:

As part of the project archetype you should have JUnit 5 (jupiter) and mockito dependencies in your POM.xml. If you don’t have those dependencies you can add it up!

Note that junit-jupiter-engine is the main JUnit 5 library

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.3.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>2.21.0</version>
    <scope>test</scope>
</dependency>

1.2 Surefire PLUGIN

Now check for the below surefire plugin to run our test classes using the new JUnit platform launcher. If you don’t have it in your POM.xml you can use the below dependency to update.

<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.19.1</version>
    <dependencies>
        <dependency>
             <groupId>org.junit.platform</groupId>
             <artifactId>junit-platform-surefire-provider</artifactId>
             <version>1.0.1</version>
         </dependency>
     </dependencies>
</plugin>
1.3 Mockito extension

Now check for the below Mockito extension dependency which provides an implementation for JUnit5 extensions in the library – mockito-junit-jupiter. If it’s not there add it up!

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>2.23.0</version>
    <scope>test</scope>
</dependency>

2. Difference between JUnit4 and JUnit5

2.1 Mock class annotations

In JUnit4 we require @RunWith annotation

@RunWith(MockitoJUnitRunner.class)

or 

@RunWith(PowerMockRunner.class)


In JUnit5 we have @ExtendWith annotation
Import Statements:
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)

or 

@ExtendWith(AemContextExtension.class)
2.2 New Java version

JUnit4 is only have features up to Java7 it doesn’t give any features of Java8 and newer versions. Whereas JUnit5 have all these features like lambda functions.

2.3 Updates in annotations

Some of the below annotations in JUnit4 are now changed in JUnit5:

  • @Before changed to @BeforeEach
  • @After changed to @AfterEach
  • @BeforeClass changed to @BeforeAll
  • @AfterClass changed to @AfterAll
  • @Ignore changed to @Disabled
2.4 chain assertion using lamda

Now using Junit5 we can chain multiple assertions in one test case.

@Test
public void chainAssertionTest() {
    List<String> list = Arrays.asList("nikhil", "kumar", "aem");
    Assertions.assertAll("Assertion message",
        () -> Assertions.assertEquals(list.get(0), "nikhil"),
        () -> Assertions.assertEquals(list.get(1), "kumar"),
        () -> Assertions.assertEquals(list.get(2), "aem"));
}


2.5 PowerMocks

Issue with JUnit5 is that there is no concrete support for Power mocks as of now. Whereas in JUnit4 PowerMocks works perfectly.

But let’s understand how we can handle some scenarios where we need PowerMocks in Junit5 as an alternative.

Lets say I have below use case for PowerMocks of when/then:

PowerMockito.when(resource.getResourceResolver()).thenReturn(resourceResolver);


We can use Mockito Extension to replace the usage of PowerMocks in Junit 5

Mockito.lenient().when(resource.getResourceResolver()).thenReturn(resourceResolver);

NOTE: Mockito.lenient() is used here as Mockito throws an UnsupportedStubbingException, when an initialised mock is not called by one of the test methods during execution. We can avoid this strict stub checking by using this method when initialising the mocks.


Also lets the usecase where we use Whitebox whic we use to set the values of some private variables who doesn’t have setter methods. Below is the Syntax that we used to use in Junit 4:

  • ConfigurationClass configurationClass = new ConfigurationClass (); –> This is my target java class instance
  • “resource” –> is the private resource variable name in the target java class.
  • @Mock
    private Resource resource; –> Mocked resource in test class


Whitebox.setInternalState(configurationClass, "resource", resource);

Now in Junit5 the Syntax would be same it’s just we will use the below second import instead of below first one:

  • import org.powermock.reflect.Whitebox; –> Used in Junit4 using PowerMocks
  • import org.mockito.internal.util.reflection.Whitebox; –> Used in Junit5 using below dependency.

    Whitebox dependency compatible with Junit5:
        <dependency>
		    <groupId>org.mockito</groupId>
		    <artifactId>mockito-all</artifactId>
		    <version>1.9.5</version>
		    <scope>test</scope>
		</dependency>

Also to use the assets statements you can use the below dependency and import statement:

        <dependency>
		    <groupId>org.mockito</groupId>
		    <artifactId>mockito-all</artifactId>
		    <version>1.9.5</version>
		    <scope>test</scope>
		</dependency>
import static org.junit.Assert.assertEquals;
assertEquals("Title", configurationClass .getTitle());
2.6 Mock static method

We cannot mock static method in Junit5 but JUnit5 provides support running legacy JUnit4, and there you can use PowerMockito. So you can create tests in Junit4 for these cases.


3. Some Important Import Statements in Junit5

Import StatementsUsage
import org.junit.jupiter.api.Assertions;Used for Assertions.
import org.junit.jupiter.api.BeforeEach;Used in place @Before(Juinit4), used before function which runs before all test cases.
import org.junit.jupiter.api.Test;Used for @Test Annotations
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
It marks the Test Case class to be run with the Mockito JUnit Jupiter Extension which allows for the use of the @Mock annotations to define mock objects at the Class level.
@ExtendWith(MockitoExtension.class)
import static org.junit.Assert.assertEquals;Used for Assertions.




Thanks for reading my article, let me know for any updates.
Also subscribe my blog to get the new articles in your mailbox.

Happy Coding!!


Author:

I am Nikhil Kumar, AEM developer. Working on AEM since the start of my career. Created this blog to share my AEM knowledge and give back to the AEM Community. You can reach out to me on any query.

Leave a comment