Migrate AEM Mocks Unit Tests from JUnit 4 to JUnit 5

Problem

AEM Mocks up to version 2.2 only supported JUnit 4. With Version 2.3.0 and up you can choose between JUnit 4 or JUnit 5, or use tests of both side-by-side.

This article describes how to migrate your unit tests using AEM Mocks and JUnit 4 to JUnit 5.

See also: adaptTo Talk 2018: JUnit 5 and Sling/AEM Mocks

Solution

Surefire Version

  • Make sure to use the latest Version of the Maven Surefire Plugin

Dependencies in POM

Remove existing dependencies to JUnit 4 from your POMs:

  • Remove all references to junit:junit
  • Remove all references to io.wcm:io.wcm.testing.aem-mock

and instead add in your parent POM:

    <dependencyManagement>
      <dependency>
        <groupId>org.junit</groupId>
        <artifactId>junit-bom</artifactId>
        <version>5.3.1</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencyManagement>

and add in the module POMs:

    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-params</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-engine</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.wcm</groupId>
      <artifactId>io.wcm.testing.aem-mock.junit5</artifactId>
      <scope>test</scope>
    </dependency>

If you want to keep some tests in JUnit 4 to run them side-by-side with JUnit 5 also add:

    <!-- Only required for JUnit 4 -->
    <dependency>
      <groupId>org.junit.vintage</groupId>
      <artifactId>junit-vintage-engine</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.wcm</groupId>
      <artifactId>io.wcm.testing.aem-mock.junit4</artifactId>
      <scope>test</scope>
    </dependency>

If you are also using Mockito in your unit tests add this dependency for Mockito JUnit 5 support:

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

Migrate JUnit-specific code

The JUnit 5 Jupiter API differs in many ways from JUnit 4 - but most of the test code can be migrated quite easy without pain. This section lists only the most common migration steps.

  1. Remove all existing package imports from your source code file starting with org.junit and insert instead:

    import static org.junit.jupiter.api.Assertions.*;
    import org.junit.jupiter.api.*;
  2. Replace @Before/@After annotations with @BeforeEach/@AfterEach
  3. In case you have provided messages to your assertXXX calls, move the message string parameter from first to last method parameter
  4. Remove expected=XYZException.class parameters from your @Test annotations, and instead wrap the code with:

        assertThrows(XYZException.class, () -> {
          ...
        });
  5. In case you are using Mocktio, remove the @RunWith annotation, and instead add:

    @ExtendWith(MockitoExtension.class)

Migration AEM Mocks-specific code

  1. For the package exports replace io.wcm.testing.mock.aem.junit.* with io.wcm.testing.mock.aem.junit5.*
  2. Remove @Rule annotation from your AemContext member variable
  3. Add AEM context extension:

    @ExtendWith(AemContextExtension.class)


Concerning OSGi Mocks, Sling Mocks

If you are not using AEM Mocks but OSGi Mocks or Sling Mocks directly (which are embedded in AEM Mocks), the procedure is quite the same, only the Maven artifacts and package names are different.