Skip to content

JUnit 5

The JVM's standard testing framework, rebuilt around an extension model.

TestingJava

What it is

JUnit 5 is a modern testing framework for Java, designed to write unit and integration tests. It provides a modular architecture, rich annotations, and support for lambda expressions and assertions.

JUnit 5 allows developers to write tests using annotations such as `@Test`, `@BeforeEach`, `@AfterEach`, `@BeforeAll`, `@AfterAll`. It supports assertions, assumptions, parameterized tests, nested tests, and extensions for advanced testing scenarios.

Licence
Eclipse Public License 2.0

When to use it

The question documentation cannot answer for you — because it cannot recommend something else.

Reach for it when

  • Any Java testing — it is the default in every build tool and IDE
  • You want parameterised tests, nested test classes and tagging

Look elsewhere when

  • Nothing meaningful — this is the baseline. Add libraries around it rather than replacing it

Installation

Add org.junit.jupiter:junit-jupiter dependency in pom.xml

Getting started

The smallest useful thing you can do with it, and what each part means.

Simple test case
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class CalculatorTest {
    @Test
    void additionTest() {
        assertEquals(5, 2 + 3);
    }
}
Defines a basic JUnit 5 test that checks if the addition of 2 + 3 equals 5.
Setup and teardown
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.AfterEach;

@BeforeEach
void setup() {
    // Code executed before each test
}

@AfterEach
void teardown() {
    // Code executed after each test
}
Demonstrates methods that run before and after each test case for setup and cleanup.

Advanced usage

Where the library earns its place over a simpler alternative.

Parameterized test
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

@ParameterizedTest
@ValueSource(ints = {1, 2, 3})
void testWithValues(int value) {
    assertTrue(value > 0);
}
Runs the same test multiple times with different input values.
Testing exceptions
@Test
void divisionByZeroTest() {
    assertThrows(ArithmeticException.class, () -> { int result = 10 / 0; });
}
Verifies that a specific exception is thrown during execution.
Nested tests
import org.junit.jupiter.api.Nested;

@Nested
class InnerTests {
    @Test
    void innerTest() {
        assertEquals(4, 2 * 2);
    }
}
Organizes tests hierarchically using nested classes for better readability.
Conditional test execution
@Test
@EnabledOnOs(OS.WINDOWS)
void runOnlyOnWindows() {
    // Test logic specific to Windows
}
Runs tests conditionally based on operating system, environment, or custom conditions.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

Test failures
Check assertions and expected results; ensure the test logic matches the intended functionality.
NoClassDefFoundError for JUnit classes
Ensure JUnit 5 dependencies are correctly added and annotation processing is enabled if needed.

Best practices

  • Write small, focused test cases for each functionality.
  • Use parameterized tests to avoid code duplication.
  • Leverage assertions to validate expected outcomes clearly.
  • Use `@BeforeEach` and `@AfterEach` for setup/cleanup and `@BeforeAll`/`@AfterAll` for global setup.
  • Integrate JUnit 5 with build tools like Maven/Gradle for automated testing pipelines.

Alternatives

Comparable options, and the reason you would pick one over the other.

Background

Why it exists, and what it was reacting to.

JUnit 5 was created to address limitations in JUnit 4 and provide a more flexible, extensible, and powerful testing framework. It consists of three modules: JUnit Platform, JUnit Jupiter, and JUnit Vintage, allowing developers to write modern tests and integrate with build tools and IDEs.