Executing JUnit 4 and JUnit 5 tests in a same build

26,507

Solution 1

JUnit 5 provides a way out of the box.

JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

Each one is a distinct project and using all of them allows to compile and execute JUnit 4 and JUnit 5 tests in a same project.

JUnit Jupiter is the combination of the new programming model and extension model for writing tests and extensions in JUnit 5.

JUnit Vintage provides a TestEngine for running JUnit 3 and JUnit 4 based tests on the platform.

The JUnit Platform serves as a foundation for launching testing frameworks on the JVM


Update : from Maven Surefire 2.22.0

From the JUnit 5 documentation :

Starting with version 2.22.0, Maven Surefire provides native support for executing tests on the JUnit Platform.

So the configuration is much simpler.
Note that the junit-4 api dependency is optional as the engine dependencies that are now required already pull a default api version (it is the case for both junit 4 and 5).

Here is a sample pom.xml.

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>david</groupId>
    <artifactId>jupiter-4-and-5-same-build</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <junit-jupiter.version>5.1.0</junit-jupiter.version>
        <!-- optional : if we want to use a junit4 specific version -->
        <junit.version>4.12</junit.version>
    </properties>
    <dependencies>
        <!--JUnit Jupiter Engine to depend on the JUnit5 engine and JUnit 5 API -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit-jupiter.version}</version>
            <scope>test</scope>
        </dependency>
        <!--JUnit Jupiter Engine to depend on the JUnit4 engine and JUnit 4 API  -->
        <dependency>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
            <version>${junit-jupiter.version}</version>
        </dependency>
        <!-- Optional : override the JUnit 4 API version provided by junit-vintage-engine -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.0</version>
            </plugin>
        </plugins>
    </build>

</project>

On my GitHub space I added a working sample maven project that you can browse/clone. URL: https://github.com/ebundy/junit4-and-5-minimal-maven-project


Old way : for Maven Surefire below 2.22.0

Here is the minimal configuration to use with Maven to configure the project to compile and run both JUnit4 and JUnit5 tests :

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>mygroup</groupId>
    <artifactId>minimal-conf-junit4-5</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <!-- JUnit 5 depends on JDK 1.8 -->
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <!--  JUnit dependency versions -->
        <junit.version>4.12</junit.version>
        <junit-vintage-engine>4.12.1</junit-vintage-engine>
        <junit-jupiter.version>5.0.1</junit-jupiter.version>
        <junit-platform.version>1.0.1</junit-platform.version>
    </properties>

    <dependencies>
        <!--JUnit Jupiter API to write and compile tests with JUnit5 -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit-jupiter.version}</version>
            <scope>test</scope>
        </dependency>
        <!-- JUnit 4 to make legacy JUnit 4 tests compile -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.19.1</version> <!-- matters until now-->
                <dependencies>
                    <!-- to let surefire to run JUnit 4 but also JUnit 5 tests -->
                    <dependency>
                        <groupId>org.junit.platform</groupId>
                        <artifactId>junit-platform-surefire-provider</artifactId>
                        <version>${junit-platform.version}</version>
                    </dependency>
                    <!-- JUnit vintage engine to run JUnit 3 or JUnit 4 tests -->
                    <dependency>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                        <version>${junit-vintage-engine}</version>
                    </dependency>
                    <!-- JUnit 5 engine to run JUnit 5 tests -->
                    <dependency>
                        <groupId>org.junit.jupiter</groupId>
                        <artifactId>junit-jupiter-engine</artifactId>
                        <version>${junit-jupiter.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>
</project>

Now mvn test compiles and runs both JUnit 4 and JUnit 5 tests.

Note 1 : the junit-vintage-engine (4.12.1) and the junit (4.12) dependencies don't specify the same exact version.
This is not an issue at all as :

  • their release are not related between them

  • junit-vintage-engine is designed to run any JUnit 3 or 4 tests.

Note 2 : maven-surefire-plugin with the 2.19.1 version matters whatever you want to compile JUnit 5 test classes or both JUnit 4 and JUnit 5 test classes.
Next version of the plugin causes indeed some exceptions during JUnit 5 tests execution but the 2.22.0 that at last solves the issue (see the first part of the answer : "Update : from Maven Surefire 2.22.0").

Solution 2

JUnit have a number of example projects at https://github.com/junit-team/junit5-samples

I had a Gradle project and following https://github.com/junit-team/junit5-samples/tree/main/junit5-migration-gradle worked for me.

https://github.com/junit-team/junit5-samples/tree/main/junit5-migration-maven is the Maven equivalent - I have not tried it but I imagine that it works too.

Share:
26,507

Related videos on Youtube

davidxxx
Author by

davidxxx

The character on my avatar is Roger from American Dad. I love this "dude" ! IMPORTANT UPDATE I am looking for a full-remote job/contract focused on these technologies : Linux, containerization (Docker/Kubernetes mainly), AWS, Java, Python, JavaScript I am a Java developer for more 10 years. Since my studies and until now, I love clean code, unit testing and good desisgn. My blog about development (Java, JavaScript, Linux, ...) : http://myjavaadventures.com/blog I use it to capture and share some development practices or concept that I find interesting. Design Pattern Among other things, I like very much design patterns. So, I try to capture and present them in Java with full personal example and unit testing. Creational patterns Design Pattern : singleton implementation in Java Behavioral patterns Design Pattern : chain of responsibility implementation in Java Design Pattern : visitor implementation in Java Structural patterns Design Pattern : adapter implementation in Java Design Pattern : decorator implementation in Java I don't update it frequently but when I think about it :)

Updated on July 09, 2022

Comments

  • davidxxx
    davidxxx almost 2 years

    In Maven projects, I have some existing tests relying on JUnit 4. I cannot migrate these tests in JUnit 5 for multiple reasons.
    Essentially, some tests depend on a library which uses JUnit 4 runner and code migration may take time.

    I would like all the same create new test classes with JUnit 5 that is now released and provides new interesting features.
    How to do that ?

    • Raedwald
      Raedwald about 5 years
      I note that several popular BDD tools do not yet run under JUnit 5.
    • davidxxx
      davidxxx about 5 years
      @Raedwald When I wrote this post, one of my issues was for Cucumber. For BDD tools that are on several languages, I notice that the standard Java is not always very well updated/supported.
  • davidxxx
    davidxxx over 6 years
    Thanks a lot Marc ! I tested with a Spring Boot project that surely added it for me. I updated.
  • Steve Gelman
    Steve Gelman about 5 years
    Something I noticed is that if you only have JUnit 4 tests, the Surfire plugin will not recognize any of them. No matter how many JUnit 4 tests are present, your project needs at least one JUnit Jupiter test to run any tests.
  • Smile
    Smile about 3 years
    junit-vintage-engine should also be in test scope.