JUnit6 とは
- Java のテスティングフレームワーク
- 2025年9月30日に JUnit5 からメジャーバージョンが上がって ver 6.0.0 がリリースされた
JUnit5 との違い
6.0.0 のリリースノート を見た感じ、メジャーバージョンは上がってるけどそこまで大きな変更ではなさそう。
(4 から 5 へのバージョンアップは根本から完全に作り直されたので大きな変更だったが、 6 は Jupiter とかのベースの仕組みとかはそのままっぽい)
5 から 6 に上げることによる非互換の変更は、大まかに以下の通り。
- Java の最低バージョンが 8 から 17 に上がった
- いくつかの非互換な修正が入った
Java の最低バージョンが 8 から 17 に上がった
- JUnit 5 は、 Java の最低バージョンが 8 だったが、 JUnit 6 からは 17 に上がっている
- JUnit 6 に上げる場合は、 Java のバージョンも 17 以上に上げる必要がある
いくつかの非互換な修正が入った
JUnit Platform
- サブコマンドを指定せずに
ConsoleLauncherを実行する機能は削除 -
--h(-hの代わり)や-help(--helpの代わり)といった非標準なConsoleLauncherオプションのサポートは削除 - JUnit 4 ベースの JUnitPlatform Runner を提供していた
junit-platform-runnerモジュールは削除 - テスト検出・実行向けの Java Flight Recorder (JFR) 用イベントを提供していた
junit-platform-jfrモジュールは削除され、junit-platform-launcherモジュールに直接統合された -
junit-platform-suite-commonsモジュールは削除され、機能はjunit-platform-suiteモジュールに統合された - Maven Surefire / Failsafe 3.0.0 未満のバージョンはサポート終了
- 以下の API は削除された
- メソッド
ReflectionSupport.loadClass(String)ReflectionUtils.readFieldValue(…)ReflectionUtils.getMethod(…)ConfigurationParameters.size()MethodSelector.getMethodParameterTypes()NestedMethodSelector.getMethodParameterTypes()-
TestPlan.add(TestIdentifier)
TestPlan.getChildren(String)
TestPlan.getTestIdentifier(String) -
EngineTestKit.execute(String, EngineDiscoveryRequest)
EngineTestKit.execute(TestEngine, EngineDiscoveryRequest)
EngineTestKit.Builder.filters(DiscoveryFilter…)
- クラス
BlacklistedExceptionsPreconditionViolationExceptionClasspathScanningSupportSingleTestExecutorLegacyReportingUtils
- コンストラクタ
ReportEntry()LauncherDiscoveryRequestBuilder()
- アノテーション
@UseTechnicalNames
- メソッド
- 以前は
junit.platform.reflection.search.useLegacySemanticsシステムプロパティで切り替え可能だった「レガシーなフィールド/メソッド探索ルール」のサポートは削除- 特定のフィールドまたはメソッドが Java 言語のルールに従って表示されるかオーバーライドされるかに関して、常に標準の Java セマンティクスに準拠するようになった
- 以下のメソッドは 型境界が柔軟化され、nullable / non-nullable の両方を扱えるようになった
ConfigurationParameters.get(String, Function)NamespacedHierarchicalStore.getOrComputeIfAbsent(N, K, Function)NamespacedHierarchicalStore.getOrComputeIfAbsent(N, K, Function, Class)
-
junit-platform-suite-commonsモジュールは削除され、その機能はjunit-platform-suiteモジュールに直接統合された -
ConversionSupportは、非推奨のLocale(String)コンストラクターで使用される形式ではなく、Locale.forLanguageTag(String)ファクトリ メソッドでサポートされている IETF BCP 47 言語タグ形式を使用して、StringをLocaleに変換するようになった -
NamespacedHierarchicalStoreのすべてのgetOrComputeIfAbsent(…)メソッドは非推奨となり、代わりに新しいcomputeIfAbsent(…)メソッドが導入された - 次の構成パラメータのいずれかに無効な値を設定すると、テスト検出が失敗するようになった
junit.platform.discovery.issue.failure.phasejunit.platform.discovery.issue.severity.critical
-
ReflectionSupportのfindNestedClasses(…)およびstreamNestedClasses(…)メソッドが返すネストされたクラスの順序について、決定論的だが意図的にわかりにくい並びで返すようになった - 実装を簡素化するために、
TestIdentifierのシリアル化サポートが下位互換性のない方法で変更された
JUnit Jupiter
- 次の非推奨 API は削除された
- クラス
MethodOrderer.Alphanumeric
- メソッド
InvocationInterceptor.interceptDynamicTest(Invocation, ExtensionContext)
- クラス
- 非推奨の構成パラメータ
junit.jupiter.tempdir.scopeはサポートされなくなった -
JAVA_8からJAVA_16までの JRE 列挙定数は、JAVA_17が新しいベースラインであるため実行時に使用できなくなり、非推奨になった- 以下は手修正が必要
-
@EnabledForJreRangeおよび@DisabledForJreRangeのminVersionとmaxVersion -
@EnabledOnJreおよび@DisabledForJreRangeのversions
-
- 以下は手修正が必要
-
@EnabledForJreRangeと@DisabledForJreRangeは、デフォルトの最小値がJAVA_17となった - テスト メソッドとの一貫性を保つために、同じ包含クラスまたはインターフェースで宣言された
@Nestedクラスは、決定論的だが意図的にわかりにくい方法で順序付けられるようになった -
junit-jupiter-migrationsupportモジュールとその含まれるクラスは非推奨となり、次のメジャーバージョンで削除される -
@CsvSourceおよび@CsvFileSourceで使用しているライブラリを univocity-parsers から FastCSV に移行した結果、不正な CSV 入力に対してスローされる例外の根本原因とメッセージが変わる場合がある- 振る舞いは変わっていないが、発生した例外の型やメッセージでハンドリングしているカスタム処理がある場合は影響を受ける可能性がある
-
@CsvFileSourceのlineSeparator属性が削除された- 行区切り文字は自動検出されるようになり、
\r、\n、\r\nのいずれも行区切り文字として扱われるようになった
- 行区切り文字は自動検出されるようになり、
-
@CsvSourceおよび@CsvFileSourceのignoreLeadingAndTrailingWhitespace、nullValuesなどの属性が、通常のフィールドだけでなくヘッダーフィールドにも適用されるようになった -
@CsvSourceおよび@CsvFileSourceでは、閉じ引用符の後の余分な文字は許可されなくなった- 例えば、引用符として一重引用符が使用されている場合、次のCSV値
'foo’INVALID,'bar'は例外をスローするようになった - これにより、不正な入力が暗黙的に受け入れられたり、誤って解釈されたりすることがなくなった
- 例えば、引用符として一重引用符が使用されている場合、次のCSV値
- 構成パラメータ
junit.jupiter.params.arguments.conversion.locale.formatのサポートが削除された- ロケール変換は、
Locale.forLanguageTag(String)ファクトリ メソッドでサポートされている IETF BCP 47 言語タグ形式を使用して常に実行されるようになった
- ロケール変換は、
-
TestTemplateInvocationContextProviderインターフェースのprovideTestTemplateInvocationContexts(ExtensionContext)メソッドの戻り値の型がStream<TestTemplateInvocationContext>からStream<? extends TestTemplateInvocationContext>に変更された - 次のメソッドの型境界は、より柔軟になり、nullable / non-nullable の両方を許可するように変更された
ExtensionContext.getConfigurationParameter(String, Function)ExtensionContext.getOrComputeIfAbsent(K, Function)ExtensionContext.getOrComputeIfAbsent(K, Function, Class)
-
ExtensionContext.StoreのすべてのgetOrComputeIfAbsent(…)メソッドは非推奨となり、代わりに新しいcomputeIfAbsent(…)メソッドが導入された - 次の構成パラメータのいずれかに無効な値を設定すると、テストの検出または実行が失敗するようになった
junit.jupiter.execution.parallel.mode.defaultjunit.jupiter.execution.parallel.mode.classes.defaultjunit.jupiter.execution.timeout.modejunit.jupiter.execution.timeout.thread.mode.defaultjunit.jupiter.extensions.testinstantiation.extensioncontextscope.defaultjunit.jupiter.tempdir.cleanup.mode.defaultjunit.jupiter.testinstance.lifecycle.default
- Kotlin 固有の
assertTimeout関数のExecutableパラメータのコントラクトがcallsInPlace(executable, EXACTLY_ONCE)からcallsInPlace(executable, AT_MOST_ONCE)に変更されたため、コンパイル エラーが発生する可能性がある
JUnit Vintage
- JUnit Vintage テスト エンジンは現在非推奨となっており、少なくとも 1 つの JUnit 4 テスト クラスが見つかった場合は INFO レベルで警告を出力する
- もともと Vintage エンジンは、移行時の一時的な利用が目的なので
JUnit 5 から 6 へのマイグレーション
5 から 6 への移行ガイドは以下。
Upgrading to JUnit 6.0 · junit-team/junit-framework Wiki · GitHub
ただ、上記ページの Overview にも書いてあるが、 6 に上げたからといって大幅な修正が必要になることはほとんどなさそう。
Migrating from JUnit 5.x.y to 6.0.0 should be much easier than migrating from 4.x to 5.x. Only APIs that have been deprecated for over two years have been removed. All other APIs continue to be supported, making version 6.0.0 a drop-in replacement in most cases.
(訳)
JUnit 5.x.yから6.0.0への移行は、4.xから5.xへの移行よりもはるかに簡単です。削除されたのは、2年以上前から非推奨となっているAPIのみです。その他のAPIは引き続きサポートされるため、ほとんどの場合、バージョン6.0.0はそのまま置き換え可能です。
上に非互換の変更を記載したが、基本的に普通に JUnit でテストを書いているだけだったら、あまり関わらなさそうな変更が多い印象。
非互換の変更一覧で心当たりのある部分があればピンポイントで対応しつつ、後はバージョン上げて動くか確かめるというよくある手順でのマイグレーションになると思われ(私見)。
機能追加
JUnit Jupiter に関して、 6.0.0 で新たに追加された機能について確認する。
リリースノートは この部分。
- 表示名(
@DisplayName)に含まれる印刷できない制御文字は、代替表現に置き換えられた-
\r><CR> -
\n><LF> - その他 >
�
-
-
@TestClassOrderとの一貫性を保つため、テストクラスで指定された@TestMethodOrderアノテーションは、@Nested内部クラスによって再帰的に継承されるようになった - 外側のクラスがそれぞれ
@TestMethodOrderまたは@TestClassOrderを介して異なる順序付けを指定した場合に、@Nestedクラスとその@Nested内部クラスのデフォルトの順序付けに戻すための新しいMethodOrderer.DefaultおよびClassOrderer.Defaultを追加 -
@CsvSourceおよび@CsvFileSourceの実装は、メンテナンスが終了した univocity-parsers から FastCSV に移行された- これにより、CSV 入力処理の一貫性が向上し、特に不正なエントリの精度が向上し、エラーレポートと全体的なパフォーマンスが向上した
-
@ParameterizedClassおよび@ParameterizedTestの表示名では、引数の名前と値のペアが、名前 = 値の形式を使用して一貫してスタイル設定されるようになった- たとえば、
fruit=appleではなくfruit = appleになる
- たとえば、
- パラメータ化テストの表示名に含まれるテキストベースの引数は、デフォルトで引用符で囲まれるようになった
- なお、引用符で囲まれたテキスト内の特殊文字はエスケープされる
- 詳細は ユーザーガイド を参照
- パラメーター化されたテストのフォールバック文字列からオブジェクトへの変換では、単一の
String引数を受け入れるファクトリの既存のサポートに加えて、単一のCharSequence引数を受け入れるファクトリメソッドとファクトリコンストラクターもサポートされるようになった - パラメーター化されたテストの
Argumentsインターフェースは、正式に@FunctionalInterfaceになった - Kotlin の
suspend修飾子をテストメソッドとライフサイクルメソッドに適用できるようになった -
ExtensionContext.Storeに新しいcomputeIfAbsent(…)メソッドが追加され、null非許容型の操作が簡素化された -
ConditionEvaluationResultAPI に提供される理由文字列は、正式に@Nullableとして宣言されるようになった
いくつか気になった部分について、実際に動きを見てみる。
表示名における制御文字の出力
package sandbox.junit6;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class HelloWorldTest {
@Test
@DisplayName("Hello\r\nWorld\b")
void helloWorld() {
int result = 1 + 1;
assertEquals(3, result);
}
}
JUnit 5
JUnit 6
- JUnit 5 のときはスペース?になって実質消えていたところが、新しい文字列に置き換わっている
ParameterizedTestの表示名
package sandbox.junit6;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class HelloWorldTest {
@ParameterizedTest
@MethodSource
void helloWorld(String text, int length) {
assertEquals(length, text.length());
}
static List<Arguments> helloWorld() {
return List.of(
Arguments.arguments("hoge", 4),
Arguments.arguments(" fuga ", 8),
Arguments.arguments("\"pi\r\nyo\"", 8)
);
}
}
JUnit 5
JUnit 6
- パラメータが
Stringだった場合にダブルクォーテーションで囲われるようになっている
Hello World(おまけ)
> gradle --version
------------------------------------------------------------
Gradle 9.2.1
------------------------------------------------------------
Build time: 2025-11-17 13:40:48 UTC
Revision: 30ecdc708db275e8f8769ea0620f6dd919a58f76
Kotlin: 2.2.20
Groovy: 4.0.28
Ant: Apache Ant(TM) version 1.10.15 compiled on August 25 2024
Launcher JVM: 25.0.1 (Eclipse Adoptium 25.0.1+8-LTS)
Daemon JVM: C:\pf\java\adoptium\jdk-25.0.1+8 (no JDK specified, using current Java home)
OS: Windows 11 10.0 amd64
plugins {
id "java"
}
java {
sourceCompatibility = "25"
targetCompatibility = "25"
}
tasks.withType(JavaCompile).configureEach {
options.encoding = "UTF-8"
}
repositories {
mavenCentral()
}
dependencies {
testImplementation(platform("org.junit:junit-bom:6.0.2"))
testImplementation("org.junit.jupiter:junit-jupiter")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
test {
useJUnitPlatform()
}
package sandbox.junit6;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class HelloWorldTest {
@Test
void helloWorld() {
int result = 1 + 1;
assertEquals(3, result);
}
}
Expected :3
Actual :2
<Click to see difference>
org.opentest4j.AssertionFailedError: expected: <3> but was: <2>
at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:158)
at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:139)
at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:201)
at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:152)
at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:147)
at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:558)
at sandbox.junit6.HelloWorldTest.helloWorld(HelloWorldTest.java:12)
- 基本的な実装方法については、特に JUnit 5 の頃と変わっている点はない



