Skip to main content

Migrate to JUnit 6

JUnit 6 was released in 2025. The main change is a baseline requirement of Java 17, which affects tests using conditional execution annotations like @EnabledOnJre and @DisabledOnJre.

Java version baseline

JUnit 6 requires Java 17 as a minimum, dropping support for Java 8, 11, and earlier versions. This impacts conditional test execution based on Java versions.

ConditionalTest.java
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledOnJre;
import org.junit.jupiter.api.condition.DisabledOnJre;
import org.junit.jupiter.api.condition.JRE;

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

class ConditionalTest {

@Test
@EnabledOnJre(JRE.JAVA_8)
void onlyOnJava8() {
assertTrue(true);
}

@Test
@EnabledOnJre(JRE.JAVA_11)
void onlyOnJava11() {
assertTrue(true);
}

@Test
@DisabledOnJre(JRE.JAVA_8)
void notOnJava8() {
assertTrue(true);
}
}
warning

With JUnit 6's Java 17 baseline, tests conditioned on Java 8-16 will never run on supported JDK versions. These annotations become dead code that should be cleaned up.

Cleaning up obsolete conditions

Tests that were disabled on old Java versions can now be unconditionally enabled.

ModernFeatureTest.java
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnJre;
import org.junit.jupiter.api.condition.JRE;

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

class ModernFeatureTest {

@Test
@DisabledOnJre({JRE.JAVA_8, JRE.JAVA_11})
void usesTextBlocks() {
String text = """
This is a
multi-line
string
""";
assertEquals(3, text.lines().count());
}

@Test
@DisabledOnJre(JRE.JAVA_8)
void usesVar() {
var list = List.of(1, 2, 3);
assertEquals(3, list.size());
}
}
info

These tests were disabled on older Java versions but can now run unconditionally since JUnit 6 requires Java 17.

Automated migration

OpenRewrite provides a recipe to automatically migrate from JUnit 5 to JUnit 6.

The Moderne CLI allows you to run OpenRewrite recipes on your project without needing to modify your build files, against serialized Lossless Semantic Tree (LST) of your project for a considerable performance boost & across projects.

You will need to have configured the Moderne CLI on your machine before you can run the following command.

  1. If project serialized Lossless Semantic Tree is not yet available locally, then build the LST. This is only needed the first time, or after extensive changes:
shell
mod build ~/workspace/
  1. If the recipe is not available locally yet, then you can install it once using:
shell
mod config recipes jar install org.openrewrite.recipe:rewrite-testing-frameworks:LATEST
  1. Run the recipe.
shell
mod run ~/workspace/ --recipe org.openrewrite.java.testing.junit6.JUnit5to6Migration
tip

OpenRewrite's JUnit5to6Migration recipe automatically:

  • Removes tests with @EnabledOnJre for Java 8-16
  • Removes @DisabledOnJre annotations for Java 8-16
  • Cleans up obsolete conditional execution logic
  • Updates JUnit dependencies to version 6.x

What hasn't changed

Despite the version number change, JUnit 6 is not a breaking change in terms of API.

info

JUnit 6 maintains API compatibility with JUnit 5:

  • All JUnit 5 APIs continue to work
  • Package names remain org.junit.jupiter.api.*
  • Annotation names and behavior are unchanged
  • The main changes are internal improvements and the Java 17 baseline

The version bump to 6 primarily reflects the breaking change in minimum Java version requirements rather than API changes.