JUnit 5 Tutorial

This JUnit 5 tutorial talks about how JUnit adapted the Java 8 style of coding and several other features. Learn how JUnit 5 is different from JUnit 4.

JUnit 5 is the most widely used testing framework for Java applications. For a very long time, JUnit has been doing its job perfectly.

In between, JDK 8 brought fascinating features in java and, most notably, lambda expressions. JUnit 5 aimed to adapt the Java 8 style of coding; that’s why Java 8 is the minimum required version to create and execute tests in JUnit 5 (though it is possible to run tests written with JUnit 3 or JUnit 4 for backward compatibility).

1. JUnit 5 Architecture

As compared to JUnit 4, JUnit 5 is composed of several different modules from three different sub-projects:

JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

  • JUnit Jupiter: It includes new programming and extension models for writing tests. It has all new junit annotations and TestEngine implementation to run tests written with these annotations.
  • JUnit Platform: To be able to launch junit tests, IDEs, build tools or plugins need to include and extend platform APIs. It defines the TestEngine API for developing new testing frameworks that runs on the platform.
    It also provides a Console Launcher to launch the platform from the command line and build plugins for Gradle and Maven.
  • JUnit Vintage: Its primary purpose is to support running JUnit 3 and JUnit 4 written tests on the JUnit 5 platform. It’s there is backward compatibility.

2. Installation

You can use JUnit 5 in your Maven or Gradle project by including a minimum of these dependencies:

  • junit-jupiter-api: It is the main module where all core annotations are located, such as @Test, Lifecycle method annotations and assertions.
  • junit-jupiter-engine: It has test engine implementation which is required at runtime to execute the tests.
  • junit-platform-suite: The @Suite support provided by this module to make the JUnitPlatform runner obsolete.
<properties>
    <junit.jupiter.version>5.8.1</junit.jupiter.version>
    <junit.platform.version>1.8.1</junit.platform.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>${junit.jupiter.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>${junit.jupiter.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-params</artifactId>
        <version>${junit.jupiter.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.platform</groupId>
        <artifactId>junit-platform-suite</artifactId>
        <version>${junit.platform.version}</version>
        <scope>test</scope>
    </dependency>
</dependencies>
dependencies {
    testRuntime("org.junit.jupiter:junit-jupiter-api:5.8.1")
    testRuntime("org.junit.jupiter:junit-jupiter-engine:5.8.1")
    testRuntime("org.junit.jupiter:junit-jupiter-params:5.8.1")
    testRuntime("org.junit.platform:junit-platform-suite:1.8.1")
}
test {
    useJUnitPlatform()
}
JUNit 5 Modules

Read More: Maven Example | Gradle Example

3. JUnit 5 Annotations

JUnit 5 offers the following annotations to write tests.

AnnotationDescription
@BeforeEachThe annotated method will be run before each test method in the test class.
@AfterEachThe annotated method will be run after each test method in the test class.
@BeforeAllThe annotated method will be run before all test methods in the test class. This method must be static.
@AfterAllThe annotated method will be run after all test methods in the test class. This method must be static.
@TestIt is used to mark a method as a junit test.
@DisplayNameUsed to provide any custom display name for a test class or test method
@DisableIt is used to disable or ignore a test class or test method from the test suite.
@NestedUsed to create nested test classes
@TagMark test methods or test classes with tags for test discovering and filtering
@TestFactoryMark a method is a test factory for dynamic tests.

4. Writing Tests

There is not much change between JUnit 4 and JUnit 5 in test writing styles. Here are sample tests with their life cycle methods.

Notice all the annotations are coming from org.junit.jupiter.api package.

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

import com.howtodoinjava.junit5.examples.Calculator;

public class AppTest {

	@BeforeAll
	static void setup(){
		System.out.println("@BeforeAll executed");
	}

	@BeforeEach
	void setupThis(){
		System.out.println("@BeforeEach executed");
	}

	@Tag("DEV")
	@Test
    void testCalcOne()
	{
		System.out.println("======TEST ONE EXECUTED=======");
		Assertions.assertEquals( 4 , Calculator.add(2, 2));
    }

	@Tag("PROD")
	@Disabled
	@Test
    void testCalcTwo()
	{
		System.out.println("======TEST TWO EXECUTED=======");
		Assertions.assertEquals( 6 , Calculator.add(2, 4));
    }

	@AfterEach
	void tearThis(){
		System.out.println("@AfterEach executed");
	}

	@AfterAll
	static void tear(){
		System.out.println("@AfterAll executed");
	}
}

5. Writing Test Suites

Using JUnit 5 test suites, you can run tests spread into multiple test classes and different packages. JUnit 5 provides these annotations to create test suites.

  • @Suite
  • @SelectClasses
  • @SelectPackages
  • @IncludePackages
  • @ExcludePackages
  • @IncludeClassNamePatterns
  • @ExcludeClassNamePatterns
  • @IncludeTags
  • @ExcludeTags

To execute the suite, you need to use @Suite annotation and include junit-platform-suite module in the project dependencies.

@Suite
@SelectPackages("com.howtodoinjava.junit5.examples")
public class JUnit5TestSuiteExample
{
}

6. Assertions

Assertions help in validating the expected output with the actual output of a test.

To keep things simple, all JUnit Jupiter assertions are static methods in the org.junit.jupiter.Assertions class e.g. assertEquals(), assertNotEquals().

void testCase()
{
    //Test will pass
    Assertions.assertNotEquals(3, Calculator.add(2, 2));

    //Test will fail
    Assertions.assertNotEquals(4, Calculator.add(2, 2), "Calculator.add(2, 2) test failed");

    //Test will fail
    Supplier&lt;String&gt; messageSupplier  = () -> "Calculator.add(2, 2) test failed";
    Assertions.assertNotEquals(4, Calculator.add(2, 2), messageSupplier);
}

Read More: JUnit 5 Assertions

7. Assumptions

Assumptions class provides static methods to support conditional test execution based on assumptions. A failed assumption results in a test being aborted.

Assumptions are typically used whenever it does not make sense to continue the execution of a given test method. In the test report, these tests will be marked as passed.

Assumptions class has three such methods: assumeFalse(), assumeTrue() and assumingThat()

public class AppTest {
    @Test
    void testOnDev()
    {
        System.setProperty("ENV", "DEV");
        Assumptions.assumeTrue("DEV".equals(System.getProperty("ENV")), AppTest::message);
    }

    @Test
    void testOnProd()
    {
        System.setProperty("ENV", "PROD");
        Assumptions.assumeFalse("DEV".equals(System.getProperty("ENV")));
    }

    private static String message () {
        return "TEST Execution Failed :: ";
    }
}

Read More: JUnit 5 Assumptions

8. Backward Compatibility for JUnit 4

JUnit 4 has been here for quite a long time, and there are numerous tests written in junit 4. JUnit Jupiter needs to support those tests as well. For this purpose, the JUnit Vintage sub-project was developed.

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

9. Conclusion

JUnit 5 feels so exciting and feature-rich. And now, it is open for extension by third-party tools and APIs. As a test writer, you may not feel that much different, but when you will go for its extension or try to develop an IDE plugin, you will praise it.

You may also consider adding test templates into eclipse IDE to improve your development speed as a developer.

Happy Learning !!

Leave a Reply

2 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial