Next-Gen App & Browser Testing Cloud
Trusted by 2 Mn+ QAs & Devs to accelerate their release cycles

Learn how to migrate from JUnit 5 to JUnit 6 with this step-by-step guide covering dependency updates, code refactoring, and OpenRewrite automated migration.

Salman Khan
March 8, 2026
With JUnit 6 releasing in September 2025, the JUnit 6 migration is now the logical next step for teams still running on JUnit 5.
JUnit 6 consolidates the previously split Jupiter, Vintage, and Platform components under a single version, eliminating dependency conflicts across Maven and Gradle modules.
How to Migrate to JUnit 6 From JUnit 5?
The migration from JUnit 5 to JUnit 6 follows a structured approach that can be done manually or through automated tools. Here are the key steps:
To migrate from JUnit 5 to JUnit 6, upgrade Java to 17+, update all JUnit dependencies to 6.0.0, refactor deprecated APIs, and validate the suite by running all tests.
The first and foremost step to start with migration to JUnit 6 is to ensure that the existing project compiles with Java 17 or newer and Kotlin 2.2 or newer. This is essential since JUnit 6 works with the upgraded baseline versions only. Without having the project built on these, there is no point in moving forward with migration.
This also involves checking and fixing the IDE and CI config and settings for the updated versions. Once this is done, simply build the project and run the existing tests to confirm they still pass. If you need a refresher on running tests, refer to this JUnit tutorial. Then you are good to go with the next step.
Once the baseline versions are upgraded, the next step of JUnit 6 migration will be to update the dependencies. You also need to refactor the code for removed or deprecated APIs and modules.
The following subsections cover the dependency changes and code-level updates required for a successful migration.
JUnit 6 consolidates multiple modules and updates dependency versions across the framework. The following changes need to be applied to your Maven or Gradle build configuration files.
Note: Run JUnit 6 tests across 3000+ real browser and OS environments at scale. Try TestMu AI Now!
Update JUnit Dependencies
Consolidate and update all the JUnit dependencies to the latest 6.0.0 (or a compatible 6.x) versions for junit-jupiter, junit-platform, and junit-vintage (if used).
For Maven, updated dependencies will look like
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>6.0.0</version>
<scope>test</scope>
</dependency>
<!-- If you still have JUnit4 tests, include Vintage too -->
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>6.0.0</version>
<scope>test</scope>
</dependency>For Gradle, similarly, make the changes and remove any JUnit 4 junit:junit dependency. The existing useJUnitPlatform() directive in your test block continues to work as-is with JUnit 6.
testImplementation("org.junit.jupiter:junit-jupiter:6.0.0")Remove External Platform Jars
If you have the following platform jars added explicitly, remove them as JUnit 6 no longer supports these.
//Remove these
junit-platform-runner
junit-platform-jfr
junit-platform-suite-commonsTheir content is now included directly in junit-platform-launcher.
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>6.0.0</version>
<scope>test</scope>
</dependency>Upgrade Build Plugins
The next step is to ensure that the versions for the Maven Surefire and Failsafe plugin are updated to 3.x or later in the build file.
Once all the dependencies are updated, the next migration step would be to refactor the test code. This makes it in accordance with the removed or changed APIs and modules.
The key areas of refactoring involve annotations, Store APIs, and method ordering implementations.
Remove Deprecated Annotations/Attributes
Remove any @EnabledOnJre(JRE.JAVA_X) or @DisabledOnJre(JRE.JAVA_X) where X < 17. These annotations are now redundant as the condition will never apply below Java 17. Also, for all the range annotations, ensure to review the range, as now 17 is the default minimum value.
@DisabledOnJre(JRE.JAVA_8) // Under Java 17, this condition never applies
void testOnlyOnJava8() { ... }Update the @CsvFileSource usage by removing the lineSeparator attribute as JUnit 6 auto-detects line endings.
//Old JUnit 5 implementation
@ParameterizedTest
@CsvFileSource(
resources = "/users.csv",
numLinesToSkip = 1,
lineSeparator = "\n"
)
//New JUnit 6 implementation
@ParameterizedTest
@CsvFileSource(
resources = "/users.csv",
numLinesToSkip = 1
)Update Removed APIs
Replace the getOrComputeIfAbsent() method of ExtensionContext.Store with the updated implementation of computeIfAbsent(). Also, review and fix the code implementation if the return value was casted previously. The new method comes with nullability annotations.
// Old JUnit 5 implementation
MyType obj = store.getOrComputeIfAbsent(MyType.class);
// New JUnit 6 implementation
MyType obj = store.computeIfAbsent(MyType.class);Also, if your suite uses the InvocationInterceptor.interceptDynamicTest() method, note that it has been removed in JUnit 6. Refactor those dynamic test interceptors using other available extension points.
Update Test Methods Ordering and Nesting
Update the test classes that have @TestMethodOrder(MethodOrderer.Alphanumeric.class) for test ordering. Use a supported orderer like MethodOrderer.MethodName.class if ordering is crucial for your execution. If not, just remove the annotation and use JUnit 6's default ordering, which is now deterministic in nature.
// Old JUnit 5 implementation
@TestMethodOrder(MethodOrderer.Alphanumeric.class)
class MyTests { ... }
// New JUnit 6 implementation with orderer
@TestMethodOrder(MethodOrderer.MethodName.class)
class MyTests { ... }
// OR
// New JUnit 6 implementation with default ordering
class MyTests { ... }Also, if you are having JUnit 5 nested test classes in your suite, the order of nested classes may now be different. JUnit 6 now enforces a deterministic but intentionally nonobvious order. In most cases, this requires no code change but needs to be verified if a certain execution order is expected.
Finally, review your junit-platform.properties file if present. Some configuration keys related to removed modules or deprecated features may need to be updated or deleted to avoid startup warnings.
For large automation suites, manually making all the changes to APIs and annotations for migrating to JUnit 6 can be time-consuming and prone to more human errors. This is where automated migration tools like OpenRewrite come to the rescue.
The OpenRewrite project provides an automated recipe that automatically reviews and refactors the entire code base for JUnit 5 to JUnit 6 migration. This recipe will
To use the OpenRewrite recipe, you would have to apply the following configuration depending on the build tool used.
Maven OpenRewrite Recipe Configuration
Step 1: Add the following to your pom.xml file.
<project>
<build>
<plugins>
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>6.26.0</version>
<configuration>
<exportDatatables>true</exportDatatables>
<activeRecipes>
<recipe>org.openrewrite.java.testing.junit6.JUnit5to6Migration</recipe>
</activeRecipes>
</configuration>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-testing-frameworks</artifactId>
<version>3.24.0</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>Step 2: Execute the following Maven command to run the recipe.
mvn rewrite:runGradle OpenRewrite Recipe Configuration
Step 1: Add the following to your build.gradle file.
plugins {
id("org.openrewrite.rewrite") version("latest.release")
}
rewrite {
activeRecipe("org.openrewrite.java.testing.junit6.JUnit5to6Migration")
setExportDatatables(true)
}
repositories {
mavenCentral()
}
dependencies {
rewrite("org.openrewrite.recipe:rewrite-testing-frameworks:3.24.0")
}Step 2: Execute the following Gradle command to run the recipe.
gradle rewriteRunThis automated approach saves a lot of effort and makes the migration even quicker for larger projects. It ensures consistency and catches many small issues that would have been missed in a manual approach.
After all the required dependency updates and code refactoring is done, the final step to complete the migration to JUnit 6 is to run the full suite and analyse the results.
There are three main areas to check during validation to ensure everything works correctly after migration.
Once done, run the entire suite again and validate the results. Repeat the process until every test passes, indicating that the suite is now successfully migrated and running on JUnit 6. With this, you are ready to leverage all the JUnit 6 updates and new features.
Once migrated, running JUnit 6 tests at scale becomes the next priority. For this, you can leverage platforms like TestMu AI for automation testing. It is a full stack quality engineering platform that lets teams execute Selenium-based JUnit tests across real browser and OS combinations without managing local infrastructure.
To get started, check out this guide on Selenium JUnit testing with TestMu AI.
Key improvements in JUnit 6 include updated Java 17 and Kotlin 2.2 baselines, unified versioning, enhanced null safety with JSpecify, upgraded FastCSV parsing, and better nested test class ordering.
A few of the key improvements in JUnit 6 are listed below.
With the JUnit 6 release, the minimum supported version for Java and Kotlin has been upgraded. The new baselines are set to Java 17 or newer (Java 8 earlier) and Kotlin 2.2 or newer (Kotlin 1.6 earlier). This improvement will help to embrace the latest Java standards by taking full advantage of the modern features in automation test cases.
One important note highlighted as per the official migration guide for this improvement says: "If your project uses earlier versions of Java and/or Kotlin, you should first switch to Java 17 or later and/or Kotlin 2.1 or later."
So before upgrading to JUnit 6, ensure that your project builds successfully with updated versions of Java and Kotlin to avoid any hiccups.
Another key change with JUnit 6 is the unified versioning for all the JUnit modules. This means now JUnit Platform, JUnit Jupiter, and JUnit Vintage all use the same version number 6.0.0. This saves the hassle of managing different version numbers for each. Also, the JUnit Vintage module now only remains a bridge if you are using JUnit 4 and is otherwise deprecated.
So in configs, you only need to update all the junit-platform-*.jar, junit-jupiter-*.jar, and (if used) junit-vintage-*.jar dependencies to 6.0.0 together.
JUnit 6 also improves the nested test classes (@Nested) implementation introduced in JUnit 5. JUnit 6 offers better default handling by ensuring a deterministic order for related tests in nested classes.
@Nested inner classes now use @TestMethodOrder(MethodOrderer.Default.class) and @ClassOrderer.Default by default. This ensures a consistent order across all runs.
This makes automation suite execution more predictable, improves execution stability, and provides results in better readable test reports.
Until JUnit 5, nullable parameters were only mentioned in JavaDoc. But with JUnit 6, JSpecify annotation standards have been added. This means any method that can take a null method parameter or have null return types can now be explicitly annotated with the @Nullable annotation. This helps
For example, the Arguments.of() method will now clearly showcase that it accepts null arguments:
static Arguments of(@Nullable Object... arguments) {
return of(arguments);
}The official JUnit migration guide suggests using NullAway or ErrorProne during the upgrade to catch any nullability issues.
JUnit 6 has upgraded the CSV parsing engine to FastCSV to improve robustness and performance while working with data-driven JUnit parameterized testing. While the majority of existing CSV implementations still remain backwards-compatible, a few modifications would be required to prevent any breaking issues.
In addition to the above, some of the additional improvements in JUnit 6 include
java -jar junit-platform-console-standalone-6.0.0.jar execute --fail-fast While most of the improvements mentioned above are backwards-compatible, JUnit 6 deprecates or changes certain modules and implementations. The ones that could impact your existing tests and need immediate attention are:
Review these carefully to identify which ones affect your codebase before starting the migration process.
As discussed, the minimum Java and Kotlin versions are now updated. So, if your project or CI still relies on Java 8-16, the tests will not work unless they are built with Java 17 or newer. Once the baseline versions are upgraded, all the below-mentioned deprecated APIs and modules can be changed one by one.
The JUnit Vintage engine used to execute JUnit 3 and 4 test cases is now deprecated. JUnit 6 will still allow you to run these old tests but will raise an INFO-level discovery warning whenever at least one such test class is found.
This warning is intended to notify users that they should plan and migrate all such test classes to the latest JUnit versions and eliminate JUnit 4 completely.
Many JUnit 5 deprecated APIs have now been removed completely from JUnit 6.
For example, any test annotated with @EnabledOnJre(JRE.JAVA_8) would always get skipped in JUnit 6. Similarly, the one with @DisabledOnJre(JRE.JAVA_8) annotation would never get skipped. This needs to be updated as per the JAVA_17 baseline for proper execution results.
Also, range-based annotations @EnabledForJreRange and @DisabledForJreRange will now have JAVA_17 as the new default minimum value. This makes @EnabledForJreRange(minVersion = 17) redundant and needs to be handled accordingly.
Any implementation that uses the now-deprecated store.getOrComputeIfAbsent(...) must be updated to call the new store.computeIfAbsent() family of methods.
// JUnit 5 style (now deprecated)
Object instance = store.getOrComputeIfAbsent(MyType.class);
// JUnit 6 replacement
Object instance = store.computeIfAbsent(MyType.class); Along with the APIs, JUnit 6 also removes some of the earlier used modules.
As JUnit 6 updates the Java baseline version to 17, build tools and plugins also need to be updated accordingly.
A few of the best practices and tips that you can follow for a quick and seamless migration from JUnit 5 to JUnit 6 are listed below.
Some of the most common issues you might face during the migration to JUnit 6, along with their root cause and fix, are listed below.
Each issue includes the error details, root cause, and the recommended fix to resolve it.
Issue: After migrating to JUnit 6, the project fails to compile with an error like
package org.junit.platform.runner does not exist
class JUnitPlatform cannot be foundReason: The junit-platform-runner module is removed in JUnit 6. Hence, the class @RunWith(JUnitPlatform.class) used in JUnit 4 integration no longer exists.
Fix: Remove the dependency and any old JUnit 4 runner usage. JUnit 6 runs Jupiter tests directly via the JUnit Platform, and no runner is needed.
<artifactId>junit-platform-runner</artifactId>
@RunWith(JUnitPlatform.class)Issue: Parameterized test cases that used to pass earlier are now throwing CSV parsing errors or unexpected failures after migrating to JUnit 6.
Reason: JUnit 6 has introduced FastCSV parser to enforce correct quoting and formatting. It has also removed the earlier used lineSeparator attribute.
Fix: Remove the unsupported lineSeparator attribute. Ensure that the test data CSV has a consistent delimiter and has no stray characters after closing quotes or malformed lines.
// Old JUnit 5 implementation
@CsvFileSource(resources = "/test.csv", lineSeparator = "\n")
// New JUnit 6 implementation
@CsvFileSource(resources = "/test.csv")Issue: Extensions that use the JUnit 5 Store API fail to compile with an error like below.
method getOrComputeIfAbsent does not existReason: JUnit 6 has removed the old getOrComputeIfAbsent() store methods. They are replaced with computeIfAbsent() methods having nullability support to ensure type-safety.
Fix: Replace the old implementation with the updated methods and handle nullability as well.
// Old JUnit 5 implementation
// <1> returns MyType
store.getOrComputeIfAbsent(MyType.class);
// <2> returns @Nullable Object
store.getOrComputeIfAbsent("key", key -> new MyType());
// <3> returns @Nullable MyType
store.getOrComputeIfAbsent("key", key -> new MyType(), MyType.class);
// New JUnit 6 implementation
// <1> returns MyType
store.computeIfAbsent(MyType.class);
// <2> returns Object
store.computeIfAbsent("key", key -> new MyType());
// <3> returns MyType
store.computeIfAbsent("key", key -> new MyType(), MyType.class);Issue: The suite is compiled successfully on CI, but CI shows 0 tests.
0 tests runReason: Either the CI or Surefire/Failsafe plugins, or both, are running on an older version. JUnit 6 fails to discover tests and run them.
Fix: Ensure that the CI is using Java 17 or newer, and Surefire/Failsafe plugin versions are updated to 3.x.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
</plugin>Issue: After migration, third-party extensions like Mockito, Spring Boot Test, or custom extensions throw NoSuchMethodError or ClassNotFoundException at runtime.
Reason: Older versions of third-party libraries may depend on JUnit 5 internal APIs that have been removed or changed in JUnit 6. They may also not be compiled for Java 17.
Fix: Update third-party testing libraries to their latest versions that declare JUnit 6 compatibility. Check the library's release notes or changelog for JUnit 6 support confirmation before upgrading.
With this, we have come to the end of this JUnit 6 migration guide. We learnt how this migration would help to evolve the suite to capitalise on all the improvements made in JUnit 6.
Remember, upgrading Java and Kotlin versions, updating build configurations, and changes to deprecated APIs, along with some minor tweaks, is all you need to do manually or with OpenRewrite for this migration to complete.
Once done, you are good to take advantage of the JUnit 6 features and create more robust automation frameworks in the Java ecosystem.
Did you find this page helpful?
More Related Hubs
TestMu AI forEnterprise
Get access to solutions built on Enterprise
grade security, privacy, & compliance