Introduction to JUnit 5 (original) (raw)

Last Updated : 26 Sep, 2025

JUnit is used testing framework for Java applications. JUnit 5, also known as JUnit Jupiter, is the latest version of the framework. Compared to JUnit 4, it provides more features, flexibility and a modern architecture for writing and executing tests.

JUnit 5 is composed of three main modules:

  1. JUnit Platform
  2. JUnit Jupiter
  3. JUnit Vintage

junit_platform_

These components collectively make it easier to define, organize and run tests efficiently.

1. JUnit Platform

The JUnit Platform is the foundation of JUnit 5. It provides a launching mechanism for running tests on the JVM. In real-world applications, the testing team designs various test cases to verify the functionality and behavior of an application. The JUnit Platform ensures that these test cases can be executed consistently on any Java Virtual Machine (JVM).

2. JUnit Jupiter

JUnit Jupiter is the module that provides new programming models and features for writing test cases in JUnit 5. It includes annotations, assertions, assumptions and more, enabling developers to write modern, clean and maintainable test code.

3. JUnit Vintage

JUnit Vintage allows you to run legacy tests written with JUnit 3 or JUnit 4 on the JUnit 5 platform. This ensures backward compatibility during the transition to JUnit 5.

Basics of JUnit 5

JUnit provides many features compared to JUnit 4. If you want to learn JUnit 5, then we need to know some basics of the JUnit 5 Framework. Now I provide the basic information about JUnit 5. The basics of JUnit 5 are,

Maven Dependency for JUnit 5

To use JUnit 5 with Maven, you need to add the following dependencies to your pom.xml:

Java `

org.junit.jupiter junit-jupiter-engine 5.9.3 test org.junit.vintage junit-vintage-engine 5.9.3 test

`

Gradle Dependency for JUnit 5

To use JUnit 5 with Gradle, you need to add the following dependencies to your build.gradle:

Java `

testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.3' testImplementation 'org.junit.vintage:junit-vintage-engine:5.9.3'

`

Annotations

The JUnit 5 framework uses different Annotations based on the test case design. Mostly in JUnit 5 @Test, @BeforeEach, @AfterEach, @BeforeAll, @AfterAll, @DisplayName, @Disabled these annotations are used. Basically, Annotations provides supplement information about the program in java. Annotations are always start with "@" symbol.

Test Life cycle methods

The JUnit 5 life cycle methods are annotated methods which are always start with @ symbol, these methods are executed at specific point in the test life cycle. The Life cycle methods are,

Assertions

The JUnit 5 provides different methods in Assertions class for checking the expected Result. Assertions are used to check if a condition is true. If the condition is false, the test fails. Common assertions include:

**Example: Java program to demonstrate JUnit Assertion

Java `

import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test;

public class MyTest { @Test void exampleTest() { int result = someMethod(); Assertions.assertEquals(42, result, "The result should be 42"); } private int someMethod() { return 42; } }

`

For above code the test case passed successfully.

Assumptions

Assumptions in JUnit 5 provides a good way for checking the test cases conditionally based on preconditions and one more is if Assumptions is failed then it is marked as skipped rather then failed. Means Assumptions are used to when you want to skip a test then we use Assumptions in JUnit 5.

**Example: Java program to demonstrate JUnit Assumption

Java `

import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test;

public class MyTest {

@Test
void exampleTest() {
    boolean condition = "true".equalsIgnoreCase(System.getProperty("runTest"));
    Assumptions.assumeTrue(condition, "Skipping the test because the condition is not met");
    int result = someMethod();
    Assertions.assertEquals(42, result, "The result should be 42");
}

private int someMethod() {
    return 42;
}

}

`

Parameterized Test

This Parameterized Test is used to test a Test case with different parameters for this we use ****@ParameterizedTest** annotations.

**Example: Java program to demonstrate parameterized test

Java `

import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import static org.junit.jupiter.api.Assertions.assertEquals;

public class MyParameterizedTest {

@ParameterizedTest
@ValueSource(ints = {1, 2, 3, 4, 5})
void testSquare(int value) {
    int result = square(value);
    assertEquals(value * value, result, "Square calculation is incorrect");
}

private int square(int number) {
    return number * number;
}

}

`

Dynamic Tests

JUnit 5 introduces the concept of dynamic tests, which can be generated at runtime. These are created using the DynamicTest class.

For creating Dynamic Tests in Run time by using @TestFactory annotation. This TestFactory provides a feature to create dynamic test case in the run time of the Application.

**Example: Java program to demonstrate Dynamic Test

Java `

import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.function.Executable;

import java.util.Collection; import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.DynamicTest.dynamicTest;

public class MyDynamicTest {

@TestFactory
Collection<DynamicTest> dynamicTestsFromStream() {
    return generateTestCases().map(input ->
            dynamicTest("Test " + input, () -> assertTrue(input % 2 == 0))
    ).toList();
}

private Stream<Integer> generateTestCases() {
    return Stream.of(2, 4, 6, 8, 10);
}

}

`

Tagging and Filtering

We can tag our test cases by using @Tag annotation in the JUnit 5. Simply the Tags are labels for categorize the test cases. And Filter is used to filter and run the test cases by using the Tags.

**Example: Java program to demonstrate Tagging and Filtering

Java `

import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertTrue;

public class TaggedTests {

@Test
@Tag("fast")
void fastTest() {
    assertTrue(true, "This is a fast test");
}

@Test
@Tag("slow")
void slowTest() {
    assertTrue(true, "This is a slow test");
}

@Test
@Tag("fast")
@Tag("integration")
void fastIntegrationTest() {
    assertTrue(true, "This is a fast integration test");
}

}

`

@AfterAll, @AfterEach and @BeforeAll, @BeforeEach

Here we will understand one example for sum of two numbers by using such as @BeforeAll, @AfterAll, @BeforeEach, @AfterEach Annotations.

Java `

import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals;

public class MySingleTestClass {

private int num1;
private int num2;

@BeforeAll
static void setupBeforeAll() {
    System.out.println("Before all tests");
}

@AfterAll
static void cleanupAfterAll() {
    System.out.println("After all tests");
}

@BeforeEach
void setupBeforeEach() {
    System.out.println("Before each test");
    num1 = 2;
    num2 = 3;
}

@AfterEach
void cleanupAfterEach() {
    System.out.println("After each test");
}

@Test
void testAddTwoNumbers() {
    System.out.println("Adding two numbers");
    int result = num1 + num2;
    assertEquals(5, result, "the sum should be 5");
}

@Test
void testAnotherMethod() {
    System.out.println("Another test method");
}

}

`

Running JUnit 5 Tests

JUnit 5 tests can be run in so many ways: